分类 编程语言 下的文章


### 3.web

以web形式查看,在web服务的时候经常被用到,需要安装gv工具,官方网页:http://www.graphviz.org/。

linux用户使用`yum install graphviz`安装即可,当然,纯命令行界面是不能查看的。

windows用户下载`msi`包安装后需要把安装目录下的`bin`目录添加到环境变量才行。

![](http://ww1.sinaimg.cn/large/005wtJ8cgy1fnapv06eeyj30dx05cdg1.jpg)

如果没有安装gv工具,使用会报错:

> Cannot find dot, have you installed Graphviz?
>
> exec: "firefox": executable file not found in $PATH

### 4.其他

其他的都是以不同形式展现出来,大同小异,以后有时间再测试。

## 四、web服务器监测

在web服务器中监测只需要在`import`部分加上监测包即可:

import(

_ "net/http/pprof"

)


当服务开启后,在当前服务环境的`http://ip:port/debug/pprof`页面可以看到当前的系统信息:

![](http://ww1.sinaimg.cn/large/005wtJ8cgy1fnaq36qbgvj3095075t8k.jpg)

点击查看具体的信息:

![](http://ww1.sinaimg.cn/large/005wtJ8cgy1fnaq36puvbj30s00c3jrv.jpg)

通常可以对服务器在一段时间内进行数据采样,然后分析服务器的耗时和性能:

go tool pprof http://:/debug/pprof/profile


使用该命令后会对服务进行30s的采样,这段时间内可以尽量多使用web服务,生成多一些统计数据。
go tool pprof http://127.0.0.1:8080/debug/pprof/profile
Fetching profile from http://127.0.0.1:8080/debug/pprof/profile
Please wait... (30s)
Saved profile in \pprof\pprof.127.0.0.1.samples.cpu.001.pb.gz
Entering interactive mode (type "help" for commands)
(pprof) top
3870ms of 4800ms total (80.62%)
Dropped 37 nodes (cum <= 24ms)
Showing top 10 nodes out of 66 (cum >= 110ms)
  flat  flat%   sum%        cum   cum%
1230ms 25.62% 25.62%     1300ms 27.08%  runtime.mapaccess1_faststr
 860ms 17.92% 43.54%      860ms 17.92%  runtime.memclrNoHeapPointers
 810ms 16.88% 60.42%     1010ms 21.04%  runtime.scanobject
 190ms  3.96% 64.38%      190ms  3.96%  runtime.heapBitsForObject
 160ms  3.33% 67.71%      190ms  3.96%  strconv.ParseInt
 140ms  2.92% 70.62%     1720ms 35.83%  business_sets/haoxingdai_qiangdan/server/handler.makeOrder4Replace
 140ms  2.92% 73.54%     1990ms 41.46%  runtime.mallocgc
 120ms  2.50% 76.04%      120ms  2.50%  runtime.heapBitsSetType
 110ms  2.29% 78.33%     1680ms 35.00%  runtime.mapassign
 110ms  2.29% 80.62%      110ms  2.29%  runtime.memhash

使用`web`命令后会生成采样时间内每个系统调用的耗时分析,可以用来分析web服务的响应时间都用在哪了:

![](http://ww1.sinaimg.cn/large/005wtJ8cgy1fnaqct4d6fj30qa0d6mz8.jpg)

经常我们都会被“常量是指针还是指针所指向的对象”这个问题所困扰。

因为在使用const 修饰指针时,指针的属性有三种状态:const int * ,int * const , const int * const ,三个状态很容易混淆。

通常,我们用名词顶层const 表示指针本身是个常量,名词底层const 表示指针所指向的对象是一个常量。

例如:

int i = 0;
const int * p1 = &i;
int *x = p1; // 错误,*x不具备底层const资格
const int *x2 = p1; // 正确,具备底层const资格
const int *x3 = &i;  // 正确,&i是int *,可以转成const int *

- 阅读剩余部分 -

一、概述

和引用一样,指针也可以和const 组合,它们组合后使得指针不能用于改变其所指对象的值。

const double p1 = 3.14;
double *ptr = &p1;  //错误,ptr是一个普通的指针,不能指向常量的地址。
const double *cptr = &p1;
*cptr = 3.14159;  //错误,不能修改*cptr的值

const 和指针组合有以下三种方式:

- 阅读剩余部分 -

一、概述

const 的引用通常被称为常量引用 ,它和非常量引用的区别为:

  • 非常量引用可以修改绑定对象的值,常量引用不能修改绑定对象的值。
  • 非常量引用时绑定对象的类型必须严格匹配,常量引用只要绑定的对象可以转换成引用的类型即可,即它的绑定值可以是表达式等等。
  • 非常量引用不能引用常量和常量引用对象,常量引用可以引用普通的常量和常量引用对象。
  • 非常量引用不能引用字面量,常量引用可以引用字面量。

- 阅读剩余部分 -

一、概述

C/C++ 使用const 关键字修饰的变量叫做常量,常量的值无法改变,在整个程序的运行期间,不会(同时也不能)被任何代码所改变。

由于常量无法改变,所以在定义时就必须被初始化,它的初始值可以是任何复杂的表达式,但不能是一个未经初始化的变量。

const int i = 1;
const int j = 2 *3;
const int k = get_max();
const int err = x;  //错误,x是一个没有初始化的变量。

- 阅读剩余部分 -

一、问题描述

windows下,time.Parse()的时区和time.Format()的时区是一致的。

但是在linux环境下,time.Parse()的默认时区是UTCtime.Format()的时区默认是本地,两者如果不处理好就会导致错误。

package main
import "time"
import "fmt"
func main(){
    t, err := time.Parse("2006-01-02 15:04:05", "2017-12-03 22:01:02")
    if err != nil{
        fmt.Println(err)
        return
    }
    fmt.Println(t)
    fmt.Println(time.Now())
    fmt.Println(time.Now().Sub(t).Seconds())
}

输出:

2017-12-03 22:01:02 +0000 UTC
2017-12-03 22:15:26.592204446 +0800 CST m=+0.003020091
-27935.407549533

很明显能看到两者的时区不同并且如果把两者时间相减结果也不符合预期。

二、解决方法

使用time.ParseInLocation()而不是time.Parse()

package main

import "time"
import "fmt"

func main(){
    localTime, err := time.ParseInLocation("2006-01-02 15:04:05", "2017-12-03 22:01:02", time.Local)
    if err != nil{
        fmt.Println(err)
        return
    }
    fmt.Println(localTime)
    fmt.Println(time.Now())
    fmt.Println(time.Now().Sub(localTime).Seconds())
}

结果:

2017-12-03 22:01:02 +0800 CST
2017-12-03 22:18:26.288174547 +0800 CST m=+0.001532618
1044.288357362

Read 23 byte data:HelloWorld
HelloMaQian


## 四、关于lseek

lseek用于设置文件指针的位置,同时也可以查看当前指针所处的位置。

如果设置的文件指针超过了文件范围,系统将会给文件申请更多的内存空间来存储这些超出的文件数据,但这要求系统要在指针所指向的位置进行一次写操作。

include "apue.h"

include <fcntl.h>

int main() {

int fd, ret;

const char *s1 = "abcdefghij";
const char *s2 = "ABCDEFGHIJ";

fd = open("test.hole", O_WRONLY | O_CREAT | O_TRUNC, 0755);
if (-1 == fd)
    err_sys("open file error");

if (write(fd, s1, 10) != 10)
    err_sys("write s1 error");
if ((ret = lseek(fd, 0, SEEK_CUR)) < 0)
    err_sys("lseek error");
printf("localtion: %d\n", ret); // 打印当前的指针位置 10

if ((ret = lseek(fd, 1000, SEEK_SET)) < 0)
    err_sys("lseek error");
printf("localtion: %d\n", ret); // 移动后的位置 1000

if (write(fd, s2, 10) != 10)
    err_sys("write s2 error");
close(fd);
return 0;

}


运行程序后输出:
./a.out
localtion: 10
localtion: 1000
ll test.hole
-rwxr-xr-x 1 ma ma 1010 May 18 11:18 test.hole # 文件大小1010字节

### 4.1 使用lseek生成指定大小的文件

根据上面所描述的`lseek`的特性,文件指针超出时会自动申请空间,因此我们可以通过它来生成一个指定大小的文件。

include "apue.h"

include <fcntl.h>

const int BT_SIZE = 1;
const int KB_SIZE = 1 << 10;
const int MB_SIZE = 1 << 20;
const int GB_SIZE = 1 << 30;

/*

  • 解析输入的文件大小
  • @size 大小字符串1g, 1m, 1k, 1
  • @return 返回解析好的字节数
  • 失败直接退出程序
    */

int parser_size(const char *size)
{

int i = 0, n = 0;
char ch; // 遍历每一个字符
while ((ch = size[i]))
{
    if ((''a'' <= ch && ch <= ''z'') || (''A'' <= ch && ch <= ''Z''))
    {
        if(size[i + 1])
            err_quit("invalid input: %s", size);
        switch (ch)
        {
        case ''b'':
        case ''B'':
            return BT_SIZE * n;
        case ''k'':
        case ''K'':
            return KB_SIZE * n;
        case ''m'':
        case ''M'':
            return MB_SIZE * n;
        case ''g'':
        case ''G'':
            return GB_SIZE * n;
        default:
            err_quit("invalid input: %c", ch);
        }
    }
    else if (''0'' <= ch && ch <= ''9'')
    {
        n = 10 * n + ch - ''0'';
    }
    else
    {
        err_quit("invalid input: %s", size);
    }
    i++;
}
return n;

}

int main(int argc, char **argv)
{

if (argc < 3)
    err_quit("Usage: ./mkfile filename size");

int sz = parser_size(argv[2]);

int fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC, 0755);
if (-1 == fd)
    err_sys("crate file error");

// 移动到指定位置的前一个字节
if (-1 == lseek(fd, sz - 1, SEEK_SET))
    err_sys("create file error");

// 写入一个字节申请内存块
if (1 != write(fd, " ", 1))
    err_sys("write data error");

close(fd);
return 0;

}


根据输入即可生成指定大小的文件:
mkdir debug && gcc main.c /apue.* -o debug/app
./debug/app test1 1g
./debug/app test2 2m
./debug/app test3 3k
./debug/app test4 4
ll
total 32K
drwxrwxr-x 2 ma ma 4.0K May 18 14:40 debug
-rw-rw-r-- 1 ma ma 1.7K May 18 14:39 main.c
-rw-rw-r-- 1 ma ma 1.7K May 18 14:35 main.c.orig
-rw-rw-r-- 1 ma ma 311 May 18 14:22 Makefile
-rwxr-xr-x 1 ma ma 1.0G May 18 14:41 test1
-rwxr-xr-x 1 ma ma 2.0M May 18 14:41 test2
-rwxr-xr-x 1 ma ma 3.0K May 18 14:41 test3
-rwxr-xr-x 1 ma ma 4 May 18 14:41 test4

不过对于文件的大小有个限制,文件最多只能`2G+`,因为此时计算出来的`sz`大小会溢出。