Python之路PythonThread,第三篇,进程3

python3 进程3

 管道

在内存中开辟一个管道空间,对多个进程可见。 在通信形式上形成一种约束;

linux 文件类型

b    c      d         -                l               s                      p

            目录   普通文件  链接        套接字           管道

multiprocessing    -----> Pipe函数

Pipe(duplex)

功能:创建一个管道

参数:duplex 默认为True 表示管道为双向管道(全双工);

           如果设置为False, 则表示管道为单向管道;

返回值:返回两个管道流对象,分配表示管道的两端;

             如果参数为True(默认),两个对象均可发送接收;

             如果为False时,则第一个对象只能接收,第二个对象只能发送;

说明:1, 向管道发送数据使用send()函数,从管道接收数据使用recv() 函数;

            2,recv() 函数为阻塞函数,当管道中数据为空时会阻塞;

             3,一次recv() ,只能接收一次send()的内容;

              4,send() 可以发送字符串数字列表等多种类型数据;

 1 from multiprocessing import Process,Pipe 
 2 import os,time
 3 
 4 #创建管道对象
 5 #当参数为False的时候child只能recv parent只能send
 6 # child_conn,parent_conn = Pipe(False)
 7 
 8 child_conn,parent_conn = Pipe()
 9 
10 #子进程函数
11 def fun(name):
12     time.sleep(1)
13     #发送一个字符串到管道
14     child_conn.send('hello' + str(name))
15     print(os.getppid(),"----",os.getpid())
16 
17 jobs = []
18 #创建5个子进程
19 for i in range(5):
20     p = Process(target = fun,args = (i,))
21     jobs.append(p)
22     p.start()
23 
24 for i in range(5):
25     data = parent_conn.recv()
26     print(data)
27 
28 for i in jobs:
29     i.join()
View Code

 

消息队列:

multiprocessing ---> Queue

在内存中开辟一个队列模型,用来存放消息,任何拥有队列队形的进程都可以进行消息的存放和取出;

Queue(maxsize = 0)

功能:创建一个消息队列对象;

参数:maxsize 默认为0 表示消息队列可以存放的消息由系统自动分配的空间而定;

                            > 0 的正整数   表示队列中最多存放多少条消息;

返回值:消息队列对象;

q.put() 

1,向消息队列中存放一条消息,当消息队列满的时候,会阻塞;

2, 存放的消息类型可以是数字,列表,字符串等;

q.full()

判断队列是否为满, 如果满则返回True,否则返回False;

q.qsize()

查看当前队列中消息数量;

q.get()

获取消息,每次获取一条; 当消息队列为空时,则为阻塞;

说明: put() 、get() 中block参数和timeout参数

block默认为True,表示两个函数都是阻塞函数;

         如果设置为False, 则表示不阻塞;

timeout  当block设置为True时,表示超时等待时间;

 1 from multiprocessing import Queue 
 2 
 3 #创建消息队列对象
 4 q = Queue(3)
 5 
 6 i = 0
 7 # 存放消息 
 8 while True:
 9     #判断队列是否满了
10     if q.full():
11         print("queue is full")
12         break
13     q.put("hello" + str(i))
14     i += 1
15 
16 print("当前队列有%d条消息"%q.qsize())
17 
18 for i in range(q.qsize()):
19     print("获取消息%s"%q.get())
20 
21 print("is empty?",q.empty())
22 
23 print(q.get(True,3))
24 
25 print("process over")
View Code
 1 from multiprocessing import Process,Queue 
 2 import time 
 3 
 4 q = Queue()
 5 
 6 def fun(name):
 7     time.sleep(1)
 8     q.put("hello" + str(name))
 9 
10 jobs = []
11 
12 for i in range(10):
13     p = Process(target = fun,args =(i,))
14     jobs.append(p)
15     p.start()
16 
17 for i in jobs:
18     i.join()
19 
20 while not q.empty():
21     print(q.get())
View Code

 

 共享内存

在内存中开辟一段内存空间存储数据,每次存储的内容会覆盖上次的内容;由于没有对内存进行格式化修饰,所以存储的速度快效率高;

from multiprocessing import Value,Array

obj = Value(ctype,  obj)

功能:开辟共享内存

参数:ctype 要转变的c的类型

            obj    要写入共享内存的初始值

obj.value 属性为获取共享内存中的值;

 1 from multiprocessing import Value,Process
 2 import time 
 3 import random 
 4 
 5 def deposite(money):
 6     for i in range(100):
 7         time.sleep(0.03)
 8         money.value += random.randint(1,200) 
 9 
10 def withdraw(money):
11     for i in range(100):
12         time.sleep(0.02)
13         money.value -= random.randint(1,150) 
14 
15 money = Value('i',2000)
16 
17 d = Process(target = deposite,args = (money,))
18 w = Process(target = withdraw,args = (money,))
19 
20 d.start()
21 w.start()
22 
23 d.join()
24 w.join()
25 
26 print(money.value)
View Code

 obj =Array(ctype, obj)

功能: 开辟一个共享内存空间;

参数: 要装的c的类型;

            obj 放入共享内存中的数据, 是一个列表,要求列表重点数据为相同类型的数据;

             如果obj传入一个正数,则表示在共享内存中开辟一个多大的空间,空间中可以存放的数值类型由ctype确定;

返回值: 返回一个可迭代对象通过for循环取值,可以进行修改;

from multiprocessing import Process,Array 
import time 
import ctypes

def fun(shm):
    for i in shm:
        print(i)
    # shm[0] = 'A'

# shm = Array('i',[1,2,3,4,5])
shm = Array(ctypes.c_char,6)

p = Process(target = fun,args = (shm,))
p.start()
p.join()

for i in shm:
    print(i)
View Code

 

 ############

                                   管道                            消息队列                            共享内存

开辟空间 :               内存中                         内存中                                  内存中

读写方式:            可双向/单向              先进先出,按照个数存储          操作内存

效率 :                          一般                             一般                                      较快

是否需要同步互斥 :  不需要                           不需要                                  需要

#############

信号:

kill    -l   查看系统信号

kill  -signame   PID  给进程号PID的进程发送signame信号;

信号:  信号名称     含义       默认处理方式

名称:系统定义

含义:系统定义

处理方式:采用默认方式处理(系统定义     终止   暂停   忽略)

                   忽略信号(当信号没发生过)

                   采用自定义方式处理

 1 import signal 
 2 import time
 3 
 4 signal.alarm(5)
 5 #采用默认方式
 6 # signal.signal(signal.SIGINT,signal.SIG_DFL)
 7 
 8 #忽略该信号
 9 signal.signal(signal.SIGINT,signal.SIG_IGN)
10 signal.signal(signal.SIGALRM,signal.SIG_IGN)
11 
12 while True:
13     time.sleep(2)
14     print("你按ctrl + c啊")
View Code

 

 1 from signal import * 
 2 import os,time 
 3 
 4 #信号处理函数,有固定参数格式
 5 def handler(sig,frame):
 6     if sig == SIGALRM:
 7         print("收到了时钟信号")
 8     elif sig == SIGINT:
 9         print("收到了SIGINE就不结束")
10 
11 alarm(7)
12 
13 #通过函数 处理信号
14 signal(SIGALRM,handler)
15 signal(SIGINT,handler)
16 
17 while True:
18     print("waiting for signal")
19     time.sleep(2)
View Code

 

如何发送信号:

os.kill(pid,   sig) 

功能:向一个进程发送一个信号

参数:pid  指要发送进程的PID号

           sig  指要发送的信号

signal.alarm(sec)

功能:给自己发送一个时钟信号(SIGALRM)

参数:esc  秒数 表示在相应的秒数后发送时钟信号

说明:1,信号是一种异步的进程间通信方式

            2,alarm函数在一个进程中如果使用多次,则后面的时钟时间会覆盖前面的时间。

信号的处理:

signal.pause()   阻塞等待一个信号的发生;

signal.signal(signum, hander)

功能: 处理信号

参数:signum  表示可以处理的信号

            hander 信号处理的方法:

                        1, 默认处理方式:SIG_DFL

                        2,忽略信号:SIG_IGN

       3,自定义的方式: function

说明:1, signal 函数也是一个异步处理信号函数;

           2, SIGSTOP 和SIKILL不能被signal函数处理;

####

僵尸进程的信号处理方案  父进程中

signal(SIGCHLD, SIG_IGN)

###

同步和互斥

临界资源:对多个进程或者线程都可见的资源,容易产生争夺,我们将这类资源叫做临界资源;

临界区:对临界资源进行操作的代码区域称之为临界区;

解决资源争夺方法: 同步   或者   互斥

同步: 同步是一种合作关系,为完成某种任务而建立的多个进程或者线程之间的协调调用,持续等待,传递消息告知资源占用情况;

互斥: 互斥是一种制约关系,当一个进程或者线程进入到临界区后会进行枷锁操作,此时其他进程或者线程无法进入到临界区,只有

            当该进程或线程使用后进程解锁,其他人才可以使用,这种技术往往是通过阻塞完成;

 

Event  事件

Event() ----> 事件对象e

e.wait() : 产生一种阻塞 ,知道e被set之后才结束阻塞
e.set() : 将e set操作 wait不再阻塞
e.is_set() : 判断e是否是被设置的状态
e.clear() : 将e 变成 没有被设置的状态

 1 from multiprocessing import Event 
 2 
 3 #生成事件对象 
 4 e = Event() 
 5 
 6 #检测事件对象,如果被设置则返回True否则返回false
 7 print(e.is_set())
 8 
 9 #设置事件对象
10 e.set()
11 
12 #提供事件的阻塞
13 e.wait()
14 
15 print("wait.....")
16 #清除对事件的设置
17 e.clear()
18 
19 e.wait()
20 
21 print("wait...wait.....")
View Code
 1 from  multiprocessing import Process,Event
 2 import time 
 3 
 4 def wait_event():
 5     print('process1要等主进程操作完我才能操作')
 6     e.wait()
 7     print('终于操作完了,该我了',e.is_set())
 8 
 9 def wait_event_timeout():
10     print('process2要等主进程操作完我才能操作')
11     e.wait(2)
12     print('我等不了了,干别的去',e.is_set())
13 
14 e = Event() 
15 
16 p1 = Process(name = 'block',\
17     target = wait_event)
18 p1.start()
19 p2 = Process(name = 'non-block',\
20     target = wait_event_timeout)
21 p2.start()
22 
23 print("假设主进程在忙碌的操作临界区")
24 time.sleep(3)
25 e.set()
26 print("主进程开放临界区")
View Code

 

 

练习:

1. 创建父子进程,分别表示司机和售票员

2. 当售票员捕捉到 SIGINT信号时 给司机发送SIGUSR1信号,
司机打印“老司机开车了”

当售票员捕捉到 SIGQUIT信号时 给司机发送SIGUSR2信号,
司机打印“系好安全带,小心甩出去”

当司机捕捉到 SIGTSTP信号时 给售票员发送SIGUSR1信号,
售票员打印“到站了,下车吧”

3. 到站后 售票员先下车(子进程先退出),然后司机下车

 1 from signal import * 
 2 from multiprocessing import Process
 3 import os
 4 import time 
 5 
 6 def saler_handler(sig,frame):
 7     if sig == SIGINT:
 8         os.kill(os.getppid(),SIGUSR1)
 9     elif sig == SIGQUIT:
10         os.kill(os.getppid(),SIGUSR2)
11     elif sig == SIGUSR1:
12         print("python学完了,出去试试吧")
13         os._exit(0)
14 
15 def driver_handler(sig,frame):
16     if sig == SIGUSR1:
17         print("老司机带你学python")
18     elif sig == SIGUSR2:
19         print("python 知识多,积累最重要")
20     elif sig == SIGTSTP:
21         os.kill(p.pid,SIGUSR1)
22 
23 def saler():
24     signal(SIGINT,saler_handler)
25     signal(SIGQUIT,saler_handler)
26     signal(SIGUSR1,saler_handler)
27     signal(SIGTSTP,SIG_IGN)
28     while True:
29         time.sleep(2)
30         print("开着python去远方")
31 
32 p = Process(name = 'zhangjie',\
33     target = saler)
34 p.start()
35 
36 # 父进程处理信号部分
37 signal(SIGUSR1,driver_handler)
38 signal(SIGUSR2,driver_handler)
39 signal(SIGTSTP,driver_handler)
40 signal(SIGINT,SIG_IGN)
41 signal(SIGQUIT,SIG_IGN)
42 
43 p.join()
View Code

 

 

 

           

 

posted on 2018-06-16 12:42  微子天明  阅读(234)  评论(0编辑  收藏  举报

导航