go signal处理

Go Signal信号处理

参考: [Go Signal信号处理]((17条消息) Go Signal信号处理_无风的雨-CSDN博客_go signal)

可以先参考官方资料[go.signal](signal package - os/signal - pkg.go.dev)

前言

信号(Signal)是Linux, 类Unix和其它POSIX兼容的操作系统中用来进程间通讯的一种方式。对于Linux系统来说,信号就是软中断,用来通知进程发生了异步事件。

当信号发送到某个进程中时,操作系统会中断该进程的正常流程,并进入相应的信号处理函数执行操作,完成后再回到中断的地方继续执行。

有时候我们想在Go程序中处理Signal信号,比如收到SIGTERM信号后优雅的关闭程序,以及 goroutine结束通知等。

Go 语言提供了对信号处理的包(os/signal)。

Go 中对信号的处理主要使用os/signal包中的两个方法:一个是notify方法用来监听收到的信号;一个是 stop方法用来取消监听。

Go信号通知机制可以通过往一个channel中发送os.Signal实现。

信号类型

各平台的信号定义或许有些不同。下面列出了POSIX中定义的信号。 Linux 使用34-64信号用作实时系统中。命令 man signal 提供了官方的信号介绍。在POSIX.1-1990标准中定义的信号列表

需要特别说明的是,SIGKILL和SIGSTOP这两个信号既不能被应用程序捕获,也不能被操作系统阻塞或忽略。

// main.go

package main

import "fmt"
import "os"
import "os/signal"
import "syscall"

func main() {

   // 创建一个os.Signal channel
   sigs := make(chan os.Signal, 1)
   //创建一个bool channel
   done := make(chan bool, 1)

	//注册要接收的信号,syscall.SIGINT:接收ctrl+c ,syscall.SIGTERM:程序退出
	//信号没有信号参数表示接收所有的信号
   signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

     //此goroutine为执行阻塞接收信号。一旦有了它,它就会打印出来。
    //然后通知程序可以完成。
   go func() {
      sig := <-sigs
      fmt.Println(sig)
      done <- true
   }()

   //程序将在此处等待,直到它预期信号(如Goroutine所示)
   //在“done”上发送一个值,然后退出。
   fmt.Println("awaiting signal")
   <-done
   fmt.Println("exiting")
}

执行 go run main.go 再敲入 ctrl+c,程序会输出

2022-10-23    
python单例模式

单例模式

简介

单例模式是指在内存中只会创建一次对象的设计模式,在程序中多次使用同一个对象且作用相同的时候,为了防止频繁的创建对象,单例模式可以让程序在内存中创建一个对象,让所有调用者都共享这一单例对象。

几种单例模式的demo

线程安全的单例模式

import threading


class Singleton(object):
    _instance_lock = threading.Lock()
    
    def __init__(self):
        pass
    
    def __new__(cls, *args, **kwargs):
        if not hasattr(Singleton, "_instance"):
            with Singleton._instance_lock:
                if not hasattr(Singleton, "_instance"):
                    Singleton._instance = object.__new__(cls)
        return Singleton._instance

使用

obj1 = Singleton()
obj2 = Singleton()

print(obj1,obj2)

# <__main__.Singleton object at 0x7fc6c6a57898> <__main__.Singleton object at 0x7fc6c6a57898>

多线程使用

def task(arg):
    obj = Singleton()
    print(obj)
for i in range(10):
    t = threading.Thread(target=task,args=[i,])
    t.start()

# <__main__.Singleton object at 0x7fc6c6a57898>
# <__main__.Singleton object at 0x7fc6c6a57898>
# <__main__.Singleton object at 0x7fc6c6a57898>
# <__main__.Singleton object at 0x7fc6c6a57898>
# <__main__.Singleton object at 0x7fc6c6a57898>
# <__main__.Singleton object at 0x7fc6c6a57898>
# <__main__.Singleton object at 0x7fc6c6a57898>
# <__main__.Singleton object at 0x7fc6c6a57898>
# <__main__.Singleton object at 0x7fc6c6a57898>
# <__main__.Singleton object at 0x7fc6c6a57898>
2022-10-23    
为什么许多器件的片选信号低电平有效,而不是高电平有效?

片选低电平有效:

主要是为了降低功率。选中信号输出时,地址译码器输出端为低电平,此时译码器不输出功率;选中信号没有输出(不选中)时,译码器输出端为高阻状态,输出消耗功率也为0。因此芯片的CS信号采用低电平有效可以最大程度减小片选控制的功率消耗。

此外,低电平有效也可以最大程度地减小干扰和保证控制的可靠性。低电平有效时,外部的任何干扰都不能进入被控制的芯片,因而保证芯片的可靠工作。这样在干扰信号能够进入芯片时是在芯片不工作时(片选无效),也就是说,干扰信号对芯片的工作没有影响。而若采用高电平有效,在芯片工作时不要说外部干扰信号能够很容易地进入芯片干扰,造成各种误动作,就连电源的任何波动都可能影响芯片的正常工作。

2022-10-23    
数据共享与持久化

在 Docker 内部以及容器之间管理数据,在容器中管理数据主要有两种方式:

  • 数据卷(Data Volumes)
  • 挂载主机目录 (Bind mounts)

数据卷

数据卷是一个可供一个或多个容器使用的特殊目录,它绕过UFS,可以提供很多有用的特性:

  • 数据卷 可以在容器之间共享和重用
  • 对 数据卷 的修改会立马生效
  • 对 数据卷 的更新,不会影响镜像
  • 数据卷 默认会一直存在,即使容器被删除

注意:数据卷 的使用,类似于 Linux 下对目录或文件进行 mount,镜像中的被指定为挂载点的目录中的文件会隐藏掉,能显示看的是挂载的 数据卷。

选择 -v 还是 -–mount 参数: Docker 新用户应该选择–mount参数,经验丰富的 Docker 使用者对-v或者 –volume已经很熟悉了,但是推荐使用–mount参数。

docker volume create my-vol # 创建一个数据卷\\
docker volume rm my-vol
docker volume ls
local  my-vol

查看数据卷的信息

$ docker volume inspect my-vol
[
    {
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
        "Name": "my-vol",
        "Options": {},
        "Scope": "local"
    }
]

启动一个挂载数据卷的容器:在用docker run命令的时候,使用–mount标记来将 数据卷 挂载到容器里。在一次docker run中可以挂载多个 数据卷。下面创建一个名为 web 的容器,并加载一个 数据卷 到容器的 /webapp 目录。

2022-10-23    
解压缩

最简单的使用tar的命令:

# 压缩
tar -jcv -f filename.tar.bz2 要被压缩的文件或目录名称

# 查询
tar -jtv -f filename.tar.bz2

# 解压缩
tar -jxv -f filename.tar.bz2 -C 欲解压缩的目录
2022-10-23    
输入输出定向

最简单的使用tar的命令:

# 压缩
tar -jcv -f filename.tar.bz2 要被压缩的文件或目录名称

# 查询
tar -jtv -f filename.tar.bz2

# 解压缩
tar -jxv -f filename.tar.bz2 -C 欲解压缩的目录

标准输入重定向

1>: 以覆盖的方法将「正确的数据」输出到指定的文件或装置上;
1>>:以追加的方法将「正确的数据」输出到指定的文件或装置上;
2>: 以覆盖的方法将「错误的数据」输出到指定的文件或装置上;
2>>:以追加的方法将「错误的数据」输出到指定的文件或装置上;

要注意:「1»」以及「2»」中间无空格。只有「>」代表1。

将正确与错误的输出分别定向到不同的文件中

使用范例:

[root@centos ~]# find /home -name .bashrc > list_rigth 2> list_err

此时屏幕不会出现任何信息,因为刚刚执行的结果中,标准正确输出被重定向到了list_right文件中,而标准错误输出被重定向到了list_err文件中。

将正确的输出在屏幕上显示,错误输出不显示

利用黑洞 /dev/null,这个东西可以吃掉任何导向这个设备的数据。

[root@centos ~]# find /home -name .bashrc 2> /dev/null
/home/gc/.bashrc
/home/lex/.bashrc
/home/www/.bashrc

正确与错误的均写入同一个文件

[root@centos ~]# find /home -name .bashrc >list 2>&1

&&与||

指令下达 说明
cmd1&&cmd2 1.若cmd1执行完毕且正确执行($?=0),则开始执行cmd2. 2. 若cmd1执行完毕且为错误($?!=0),则cmd2不执行。
cmd1||cmd2 1.若cmd1执行完毕且正确执行,则cmd2不执行。2.若cmd1执行完毕且错误,则开始执行cmd2.
2022-10-23    
centos磁盘扩容

参考网站: https://www.cnblogs.com/fatt/p/6646773.html

2022-10-19    
docker run命令详解

命令格式:docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

Usage: Run a command in a new container

中文意思为:通过run命令创建一个新的容器(container)

示例

  • 运行一个在后台执行的容器,同时,还能用控制台管理:docker run -i -t -d ubuntu:latest
  • 运行一个带命令在后台不断执行的容器,不直接展示容器内部信息:docker run -d ubuntu:latest ping www.docker.com
  • 运行一个在后台不断执行的容器,同时带有命令,程序被终止后还能重启继续跑,还能用控制台管理,docker run -d --restart=always ubuntu:latest ping www.docker.com
  • 为容器指定一个名字,docker run -d --name=ubuntu_server ubuntu:latest
  • 容器暴露80端口,并指定宿主机80端口与其通信(: 之前是宿主机端口,之后是容器需暴露的端口),docker run -d --name=ubuntu_server -p 80:80 ubuntu:latest
  • 指定容器内目录与宿主机目录共享(: 之前是宿主机文件夹,之后是容器需共享的文件夹),docker run -d --name=ubuntu_server -v /etc/www:/var/www ubuntu:latest
2022-10-19    
docker启动命令逆向输出

主要依靠的一个开源软件runlike

See runlike-github


yum clean all
yum makecache

yum install python-pip python-setuptools -y

pip install runlike

# 若此时正在运行的一个容器为`redis`
# 则
runlike redis > redis_start.sh
# 此时redis_start.sh即为docker启动redis容器的命令
2022-10-19    
docker网络

容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过-P-p参数来指定端口映射。

当使用-P标记时,Docker会随机映射一个端口到内部容器开放的网络端口。

使用docker container ls 可以看到,本地主机的32768被映射到了容器的80端口。此时访问本机的32768端口即可访问容器内nginx的默认页面。

$ docker run -d -P nginx:alpine

$ docker container ls -l
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                   NAMES
fae320d08268        nginx:alpine        "/docker-entrypoint.…"   24 seconds ago      Up 20 seconds       0.0.0.0:32768->80/tcp   bold_mcnulty

同样的,可以通过docker logs命令来查看访问记录。

$ docker logs fa
172.17.0.1 - - [25/Aug/2020:08:34:04 +0000] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0" "-"

-p 则可以指定要映射的端口,并且,在一个指定端口上只可以绑定一个容器。支持的格式有ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort

映射所有接口地址

使用hostPort:containerPort 格式将本地的80端口映射到容器的80端口,可以执行

$ docker run -d -p 80:80 nginx:alpine

映射到指定地址的指定端口

可以使用ip:hostPort:containerPort 格式指定映射使用一个特定地址,比如localhost地址127.0.0.1

2022-10-19