Python网络编程(进程通信、信号、线程锁、多线程)

329 阅读9分钟
原文链接: click.aliyun.com
什么是进程通讯的信号?
用过Windows的我们都知道,当我们无法正常结束一个程序时, 可以用任务管理器强制结束这个进程,但这其实是怎么实现的呢? 同样的功能在Linux上是通过生成信号和捕获信号来实现的, 运行中的进程捕获到这个信号然后作出一定的操作并最终被终止。 信号是UNIX和Linux系统响应某些条件而产生的一个事件, 接收到该信号的进程会相应地采取一些行动。通常信号是由一个错误产生的。 但它们还可以作为进程间通信或修改行为的一种方式, 明确地由一个进程发送给另一个进程。一个信号的产生叫生成,接收到一个信号叫捕获
什么是线程锁?         1.在单一进程的情况下可以叫单进程也可以叫单线程          2. 线程锁的大致思想是:如果线程A和线程B会执行实例的两个函数a和b 如果A必须在B之前运行,那么可以在B进入 b函数时让B进入wait set,直到A执行完a函数再把B从wait set中激活。这样就保证了B必定在A之后运行,无论在之前它们的时间先后顺序是怎样的。         3. 线程锁用于必须以固定顺序执行的多个线程的调度 线程锁的思想是先锁定 后序线程,然后让线序 线程完成任务再解除对后序 线程的锁定。 信号:     一个进程通过信号的方式传递某种讯息,     接收方收到信号后作出相应的处理     kill -sig pid:通过pid发送信号杀死指定进程     kill -l查看操作系统内所所有sig信号 关于信号:     信号名称: 系统定义,名字或数字     信号含义:系统定义,信号的作用     默认处理方法:           当一个进程接收到信号时默认产生的效果   进程终止暂停进程、忽略法发生     SIGHUP:    断开链接     SIGINT:      Ctrl + c     SIGQUIT:    Ctrl + \     SIGTSTP :   Ctrl + z     SIGKILL:     终止进程且不能被处理     SIGSTOP:   暂停进程且不能被处理     SIGALRM:  时钟信号     SIGCHLD:  子进程改变状态时父进程会收到此信号
Python信号处理:(signal模块)     os.kill(pid,sig)       功能:   发送一个信号给某个进程       参数:           pid:给那个进程发送信号(进程pid)   sig:要发送的信号类型     signal.alarm(sec)        功能:           异步执行           设置时钟信号   在一定时间后给自己发送一个SIGALRM信号   一个进程只能挂起一个时钟   重新挂起时钟会覆盖之前时钟        参数:           sec:时间(秒)     signal.pause()         功能:    阻塞进程,等待一个信号     signal.signal(sig,handler)         功能:信号处理 参数:    sig:要处理的信号    handler:信号处理方法        可选值:           SIG_DFL  表示使用默认方法处理   SIG_IGN  表示忽略这个信号   func     自定义函数        自定义函数格式:              def func(sig,frame):         sig:收到的信号 frame:信号结构对象         signal函数一个异步处理函数,只要执行了该函数 则进程任意时候接受到相应的信号都会处理 signal不能处理SIGKILL 、SIGSTOP父进程中可以使用 signal(SIGCHLD,SIG_IGN) 将子进程退出交给系统处理
程序的异步和同步执行:     (单进程的同步异步)     同步:        程序按照步骤一步步执行,呈现一个先后性的顺序     异步:        信号是唯一一个内部通信方式        程序在执行中利用内核功帮助完成必要的辅助操作        不影响应用层的持续执行        信号是一种异步的进程间通讯方法

示例:
from signal import * 
import time 

def handler(sig,frame):  # 自定义处理信号
    if sig == SIGALRM:  # 判断信号类型
        print("收到时钟信号")
    elif sig == SIGINT:
        print("就不结束 略略略~")

alarm(5)  # 设置5秒时钟信号

signal(SIGALRM,handler)
signal(SIGINT,handler)  #  Ctrl + C

while True:
    print("Waiting for a signal")
    time.sleep(2)




信号量:     给定一定的数量,对多个进程可见,     并且多个进程根据信号量的多少确定不同行为
    sem = Semaphore(num)         功能:创建信号量 参数:信号量初始值 返回值:信号量对象     sem.acquire()         将信号数量减1  当数量为0时阻塞     sem.release()         将信号量加1     sem.get_value()         获取当前信号量的值(数量
同步互斥机制     目的:        解决共有资源产生的资源争夺     临界资源:          多个进程或线程都可以操作的资源     临界区:         操作临界资源的代码段     同步:         同步一种合作关系,为完成某个任务, 多进程或者多个线程之间形成的一种协调 按照约定执行,相互告知,共同完成任务     互斥:         互斥一种制约关系,当一个进程或者线程 进入临界区操作资源时采用上锁的方式, 阻止其他进程操作,直到解锁后才能让出资源
Event事件:   from multiprocessing import Event   创建事件对象       e = Event()   事件阻塞       e.wait([timeout])         功能:    使进程处于阻塞状态,直到事件对象被set   事件设置:       e.set.()          功能:    让事件对象变为被设置状态   清除设置:       e.clear()          功能:使事件对象清除设置状态   事件判断:       e.is_set()         判断当前事件是否被set
示例:

from multiprocessing import Process,Event 
from time import sleep

def wait_event(file):
    print("准备操作临界资源")
    e.wait()  # 等待主进程执行结束后set
    print("开始操作临界资源",e.is_set())
    fw = open('1.jpg','wb')
    with open(file,'rb') as f:  # 复制图片
        fw.write(f.read())

def wait_event_timeout(file):
    print("也想操作临界资源")
    e.wait(2)  # 等待主进程执行set并进行2秒超时检测
    if e.is_set():
        print("也开始操作临界资源")
        fw = open('2.jpg','wb')
        with open(file,'rb') as f:  # 复制图片
            fw.write(f.read())
    else:
        print("等不了了,不等了")
# 创建事件
e = Event()
path = "/home/tarena/file.jpg"
file = 'file.jpg'

# 创建两个进程分别复制两个图片
p1 = Process(target = wait_event,args = (file,))
p2 = Process(target = wait_event_timeout,args = (file,))

p1.start()
p2.start()

# 主进程先复制图片 让子进程进入wait状态
print("主进程在操作临界资源")
sleep(3)
fw = open(file,'wb')
with open(path,'rb') as f:
    fw.write(f.read())
fw.close()
e.set()  # 子进程set
print("主进程操作完毕")


p1.join()
p2.join()


锁 Look multiprocessing --> Look   创建对象:       Lock = Lock()   lock.acquire()  上锁   lock.release()      解锁   如果一个锁对象已经被上锁调用会阻塞
multiprocessing 创建的子进程不能用input  会报错
示例:
from  multiprocessing import Process,Lock 
import sys 
from time import sleep 

#sys.stdout作为标准输出流是多个进程共有的资源

def writer1():
    lock.acquire()  #上锁
    for i in range(5):
        sleep(1)
        sys.stdout.write("writer1输出\n")
    lock.release() #解锁
# 虽然都sleep1秒但是 若不加锁会每1秒打印两次
# 由于上锁原因 w1执行完临界区w2才能被执行 一秒一次
def writer2():
    with lock:
        for i in range(5):
            sleep(1)
            sys.stdout.write("writer2输出\n")

#创建锁
lock = Lock()

w1 = Process(target = writer1)
w2 = Process(target = writer2)

w1.start()
w2.start()

w1.join()
w2.join()



多线程:     什么是线程(thread)       线程也是一种多任务编程方式,可以使用计算机的多核资源       线程被称为轻量级的进程      线程的特征:       1.一个进程可以 包含多个线程       2.线程是计算机内核使用的最小单位       3.线程也是一个运行过程,也要消耗计算机资源       4.多个线程共享共用进程的资源       5.线程也有自己特征属性TID指令集线程栈       6.多个线程之间独立运行互不干扰 空间不独立(都消耗进程空间)       7.线程的创建删除消耗的资源小于进程 线程/进程(1/20
threading 模块   threshold.Thread()     功能:        创建线程对象     参数:        target   线程函数        name    线程名 默认为Thread-1...        args      元组给线程函数位置传参        kwargs  字典给线程函数键值传参     返回值:        线程对象   t.start() 启动线程   t.join()  回收线程
  线程对象属性:       t. name 线程名       t. setName() 设置线程名称       t. is_alive()查看线程状态       threading.currentThread() 获取当前进程对象       t.daemon属性           默认False主线程的退出不会影响分支线程的执行   设置为True时主线程退出分支线程也退出 设置daemon值   t.setDaemon(True)   t.daemon = True 查看daemon值   t.isDaemon
创建自己的线程类;    1.继承Thread    2.加载父类__init__    3.重写run
示例:     
from threading import Thread 
from time import sleep, ctime

# 创建一个MyThread类继承Thread
class MyThread(Thread):
    def __init__(self, target, name = "Tedu", args = (), kwargs = {}):
        super().__init__()  # 重新加载父类的__init__初始化方法
        self.target = target 
        self.name = name
        self.args = args
        self.kwargs = kwargs

    def run(self):  # 在创建对象时自动调用run方法
# 在调用run时调分支线程要执行的线程函数  以*元组和**字典的方式接收万能传参
        self.target(*self.args, **self.kwargs)


#线程函数
def player(song,sec):
    for i in range(2):
        print("Playing %s : %s"%(song, ctime()))
        sleep(sec)

# 用自定义类创建线程并执行
t = MyThread(target = player, args = ("卡路里", 3))
t.start()
t.join()