golang 调试中碰到的结构体指针和值指针使用不同

Golang结构体的值在引用变量和之变量都可以用a.b这样使用,所以在使用的时候这样写了

func test(u string) (bi *Str) {
    bi.Em = ui.em
    bi.E2 = ui.E2
    return
}

然后返回

invalid memory address or nil pointer dereference

百思不解后突然想是不是只改了只想值指针的值内容,结构体本身还是一个空指针,于是这样写

func test(u string) (bi *Str) {
    bi = &Str{
        Em:ui.em,
        E2:ui.E2
    }
    return
}

成功

Golang管道死锁调试学习

Golang没有缓冲的管道是会等待输出才能输入,看到一个案例想调试了一下

package main

import (
    "fmt"
)

var ch1, ch2 chan int

func send() {
    ch1 <- 1
    ch2 <- 2
}

func main() {
    go send()

    fmt.Println(`ch1`, <-ch1)
    fmt.Println(`ch2`, <-ch2)
}

执行

fatal error: all goroutines are asleep - deadlock!

想这个是顺序执行的,怎么会死锁,然后发现channel和map slice一样,需要make后才能使用
修改:

package main

import (
    "fmt"
)

var ch1, ch2 chan int

func send() {
    ch1 <- 1
    ch2 <- 2
}

func main() {
    ch1 = make(chan int)
    ch2 = make(chan int)
    go send()

    fmt.Println(`ch1`, <-ch1)
    fmt.Println(`ch2`, <-ch2)
}

正常返回

ch1 1
ch2 2

替换ch1 ch2发送顺序,不改变接受顺序

func send() {
    ch2 <- 2
    ch1 <- 1
}

执行

fatal error: all goroutines are asleep - deadlock!

死锁再现,因为先发送了管道ch2,先接收ch1,因为ch1没有发送,协程卡主,就导致主线程ch1 没法发送, 死循环,生成了死锁。

第一章 计算机系统漫游

1.1 信息就是位 + 上下文

只由ASCII字符构成的文件称为文本文件,所有其他文件都称为二进制文件。
作为程序员,我们需要了解数字的机器表示方式,因为它们与实际的整数和实数是不同的,它们是对真值的有限近似值

1.2 程序被其他程序翻译成不同的格式

每条C语句都必须被其他程序转化为一些列的低级机器语言指令。然后这些指令按照一种称为可执行目标程序的格式打好包,并以二进制磁盘文件的形式存放起来。目标程序也称为可执行目标文件。
在Unix系统上,从源文件到目标文件的转化是编辑器驱动程序完成的。
gcc -o hello hello.c

这个翻译过程分为四个阶段

  1. 预处理阶段
    预处理器cpp根据以字符#开头的命令,修改原始的C程序。比如读取#include<stdio.h> 命令告诉预处理器读取系统头文件stdio.h的内容并把它直接插入程序文本中。
  2. 编译阶段
    编译器ccl把文本文件hello.i翻译成文本文件hello.s,它包含一个汇编语言程序。
  3. 汇编阶段
    汇编器al 把hello.s 翻译成机器语言指令,把这些指令打包成一种叫做可重定位目标程序的格式,并把结果保存在目标文件hello.o中。hello.o文件是一个二进制文件
  4. 链接阶段
    hello调用了printf,printf函数存在于一个名为printf.o的单独的预编译器好了的目标文件中,而这个文件必须以某种方式合并到我们的hello.o程序中。

1.4 处理器读并解释储存在内存中的指令

shell是一个命令行解释器,它输出一个提示符,等待输入一个命令行,然后执行这个命令。如果该命令行的第一个单词不是内置的shell命令,那么shell就会假设这是一个可执行文件的名字,它将加载并运行这个文件。

1.4.1 系统的硬件组成

  1. 总线
    贯穿整个系统的是一组电子管道,称作总线,它携带信息字节并负责在各个部件间传递。通常总线被设计成传送定长的字节块,也就是字。字中的字节数是一个基本的系统参数,各个系统中都不尽相同。
  2. I/O设备
    I/O设备是系统与外部世界的联系通道。主要的I/O设备:键盘 鼠标 显示器 磁盘
    每个I/O设备都通过一个控制器或适配器与I/O总线项链。控制器是I/O设备本身或者系统主印制电路板(主板)上的芯片组。适配器则是一块插在主板插槽上的卡。
  3. 主存
    主存是一个临时存储设备,在处理器执行程序时,用来存放程序和程序处理的数据。从物理上来说,主存是由一组动态随机存取存储器(DRAM)芯片组成的。从逻辑上来说,存储器是一个线性的字节数组,每个字节都有其唯一的地址(数组索引)。
  4. 村里器
    CPU,是解释执行存储在主存中的引擎。处理器的核心是一个大小为一个字的存储设备(或寄存器),称为程序计数器PC。在任何时候PC都指向主存中的某条机器语言指令。
    处理器从程序计数器指向的内存处读取指令,解释指令中的位,执行该命令指示的简单操作,然后更新PC,使其指向下一条指令,而这条指令并不一定和内存中刚刚执行的指令相邻。
    这样的操作围绕着主存,寄存器文件和算术/逻辑单元(ALU)进行。寄存器文件是小的存储设备,由一些单个字长的寄存器组成,每个寄存器都有唯一的名字。ALU计算新的数据和地址值

CPU可能执行的操作

  • 加载: 从主存复制一个字节或者一个字到寄存器,以覆盖寄存器原来的内容
  • 存储: 从寄存器复制一个字节或者一个字到主存的某个位置,已覆盖这个位置上原来的内容
  • 操作:把两个寄存器的内容复制到ALU,ALU对这两个字做算术运算,并将结果存放到一个寄存器中,以覆盖该寄存器中原来的内容
  • 跳转: 从指令本身中抽取一个字,并将这个字复制到程序计数器PC中,以覆盖PC原来的值

定时任务不能确认完成时间的解决方法

Linux 命令行常用编辑快捷键

ctrl + ? 撤消前一次输入
ctrl + c 另起一行
ctrl + r 输入单词搜索历史命令
ctrl + u 删除光标前面所有字符相当于VIM里d shift+^
ctrl + k 删除光标后面所有字符相当于VIM里d shift+$

删除
ctrl + d 删除光标所在位置上的字符相当于VIM里x或者dl
ctrl + h 删除光标所在位置前的字符相当于VIM里hx或者dh
ctrl + k 删除光标后面所有字符相当于VIM里d shift+$
ctrl + u 删除光标前面所有字符相当于VIM里d shift+^
ctrl + w 删除光标前一个单词相当于VIM里db
ctrl + y 恢复ctrl+u上次执行时删除的字符
ctrl + ? 撤消前一次输入
alt + r 撤消前一次动作
alt + d 删除光标所在位置的后单词
移动
ctrl + a 将光标移动到命令行开头相当于VIM里shift+^
ctrl + e 将光标移动到命令行结尾处相当于VIM里shift+$
ctrl + f 光标向后移动一个字符相当于VIM里l
ctrl + b 光标向前移动一个字符相当于VIM里h
ctrl + 方向键左键 光标移动到前一个单词开头
ctrl + 方向键右键 光标移动到后一个单词结尾
ctrl + x 在上次光标所在字符和当前光标所在字符之间跳转
alt + f 跳到光标所在位置单词尾部
替换
ctrl + t 将光标当前字符与前面一个字符替换
alt + t 交换两个光标当前所处位置单词和光标前一个单词
alt + u 把光标当前位置单词变为大写
alt + l 把光标当前位置单词变为小写
alt + c 把光标当前位置单词头一个字母变为大写
^oldstr^newstr 替换前一次命令中字符串
历史命令编辑
ctrl + p 返回上一次输入命令字符
ctrl + r 输入单词搜索历史命令
alt + p 输入字符查找与字符相接近的历史命令
alt + > 返回上一次执行命令
其它
ctrl + s 锁住终端
ctrl + q 解锁终端
ctrl + l 清屏相当于命令clear
ctrl + c 另起一行
ctrl + i 类似TAB健补全功能
ctrl + o 重复执行命令
alt + 数字键 操作的次数
搜索操作快捷键
搜索历史命令的快捷键:Ctrl + r
它是通过关键字去匹配历史记录,执行后会提示:(reverse-i-search)`’:
输入你记得的关键字去匹配,如果出现你需要的命令,按Enter就可以选择命令;如果不是请输入更精确的关键字去匹配。
移动操作快捷键
Ctrl + f– 向右移动一个字符,当然多数人用→
Ctrl + b– 向左移动一个字符, 多数人用←
ESC + f– 向右移动一个单词,MAC下建议用ALT + →
ESC + b– 向左移动一个单词,MAC下建议用ALT + ←
Ctrl + a– 跳到行首
Ctrl + e– 跳到行尾
删除操作快捷键
Ctrl + d– 向右删除一个字符
Ctrl + h– 向左删除一个字符
Ctrl + u– 删除当前位置字符至行首(输入密码错误的时候多用下这个)
Ctrl + k– 删除当前位置字符至行尾
Ctrl + w– 删除从光标到当前单词开头
命令切换操作快捷键
Ctrl + p– 上一个命令,也可以用↑
Ctrl + n– 下一个命令,也可以用↓
其他操作快捷键
Ctrl + y– 插入最近删除的单词
Ctrl + c– 终止操作
Ctrl + d– 当前操作转到后台
Ctrl + l– 清屏 (有时候为了好看)

部分命令记录


netstat -nat|grep -i "80"|wc -l

kill -9 `ps -ef |grep cli|awk '{print $2}’`

vim 查看第n行   :n

bg命令后台执行
fg命令前台执行

ps -aux | grep
ps -ef | grep

ln -s f1 f3  f1源文件

Git服务器配置指定客户端免密

服务器上切换到git账号

su git

设置

cd ~/.ssh
vim authorized_keys

把客户端.ssh/id_rsa.pub 的密钥复制到上面的文件中

附1·上本地生成秘钥方法
二、生成SSH密钥过程:
1.查看是否已经有了ssh密钥:cd ~/.ssh
如果没有密钥则不会有此文件夹,有则备份删除
2.生存密钥:
$ ssh-keygen -t rsa -C “haiyan.xu.vip@gmail.com”
按3个回车,密码为空。

Your identification has been saved in /home/tekkub/.ssh/id_rsa.
Your public key has been saved in /home/tekkub/.ssh/id_rsa.pub.
The key fingerprint is:
………………

最后得到了两个文件:id_rsa和id_rsa.pub

3.添加密钥到ssh:ssh-add 文件名
需要之前输入密码。
4.在github上添加ssh密钥,这要添加的是“id_rsa.pub”里面的公钥。

附2·
设置Git的user name和email:
$ git config –global user.name “xuhaiyan”
$ git config –global user.email “haiyan.xu.vip@gmail.com

Mac OS MySQL重置root密码

Mac 安装MySQL后root密码丢失后重置步骤:

cd /usr/local/mysql/bin/

sudo su

./mysqld_safe --skip-grant-tables & #进制MySQL验证

可以另起终端启动MySQL

usr/local/mysql/support-files/mysql.server start

原终端执行重置密码命令

./mysql

FLUSH PRIVILEGES;

SET PASSWORD FOR 'root'@'localhost' = PASSWORD('你的新密码');

node.js搜索bigint字段失败

使用node.js搜索数据库,发现每次搜到的bigint字段的值都会被处理,因为db包上面包了一层knex.js,还以为是knex.js的问题。查看文档:
knex官方文档
没有发现有说明这个问题,咨询同事,被提醒可能是MySQL包的问题。
搜索后发现
supportBigNumbers-处理大数字(BIGINT和DECIMAL)时需要启动此项(默认false)
bigNumberStrings-使用supportbignumbers和bignumberstrings时总是返回JavaScript字符串对象(默认false)

于是配置调整加上了supportBigNumbers:true

config = {
        "host":     "",
        "user":     "",
        "password": "",
        "supportBigNumbers" : true
    }

node-mysql 模块介绍资料地址

定时任务不能确认完成时间的解决方法

有些脚本因为要循环的执行,比如每天执行一次,或者执行完后重新执行一次,使用crontab设置定时任务指定每天执行时间。

但是这样存在一个问题,如果一个脚本一天执行不完,这样第二天到了时间会开启第二个脚本执行,会有重叠执行的情况,而其实可能需要的情况只是第一次执行完后执行第二次,不一定需要指定时间执行。

仔细想了一下发现其实被crontab的定时指定给局限了思路,另外的思路是写一个脚本监听进程,使用crontab每隔一段时间监听,看进程是否还存在,不存在则重新启动。

脚本可以如下:

 #!/bin/bash
PID=$(ps aux|grep "进程特殊标示(最好奇怪一点不要用通用的脚本名,负责监听无效)"| grep -v grep | awk '{printf $2}')
if [ $PID > 0 ]; then
    echo $PID
    exit
fi
# 重启脚本命令

golang 带header的post请求

因为今日头条的开放品台不能进行开发者资质认证了,所以只能抓包看一下发表文章的接口,因为肯定是要登录才能正常请求的,所以必须要传cookie等一些header信息的
就以存草稿为例:

func main() {
    param := map[string]string{
        `article_type`:           `0`,
        `title`:                  ``,
        `content`:                ``,
        `activity_tag`:           `0`,
        `title_id`:               `0`,
        `claim_origin`:           `0`,
        `article_ad_type`:        `3`,
        `add_third_title`:        `0`,
        `recommend_auto_analyse`: `0`,
        `tag`:                    `news`,
        `article_label`:          `0`,
        `is_fans_article`:        `0`,
        `quote_hot_spot`:         `0`,
        `govern_forward`:         `0`,
        `push_status`:            `0`,
        `push_android_title`:     ``,
        `push_android_summary`:   ``,
        `push_ios_summary`:       ``,
        `timer_time`:             `2018-11-01 03:21`,
        `column_chosen`:          `0`,
        `pgc_id`:                 ``, //article_id
        `qy_self_recommendation`: `0`,
        `pgc_feed_covers`:        ``,
        `need_pay`:               `0`,
        `from_diagnosis`:         `0`,
        `save`:                   `0`,
    }

    var paramString string
    for k, v := range param {
        paramString += k + `=` + v + `&`
    }
    paramString = strings.TrimSuffix(paramString, `&`)
    fmt.Println(paramString)
    url := "https://mp.toutiao.com/core/article/edit_article_post/?source=mp&type=article"
    client := &http.Client{}
    req, err := http.NewRequest("POST", url, strings.NewReader(paramString))
    if err != nil {
        print(err)
    }
    req.Header.Set("Cookie", ``)
    req.Header.Set("Pragma", "no-cache")
    // req.Header.Set("Accept-Encoding", "gzip, deflate, br")
    req.Header.Set("Accept-Language", "zh-CN,zh;q=0.8")
    req.Header.Set("Upgrade-Insecure-Requests", "1")
    req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36")
    req.Header.Set("Accept", "text/javascript, text/html, application/xml, text/xml, */*")
    req.Header.Set("Connection", "keep-alive")
    req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
    req.Header.Set("Cache-Control", "no-cache")

    resp2, err := client.Do(req)
    if err != nil {
        fmt.Println(`http error`, err)
    }

    body, err := ioutil.ReadAll(resp2.Body)
    if err != nil {
        fmt.Println(`get data error`, err)
    }
    fmt.Println(`body`, string(body))
}

中间文章内容格式需要根据页面操作结果慢慢调试一下的