OK上一篇的内容大家都记住了吗? 嫌多吗! 不要急,今天继续,哈哈,没事,最后几个了
本篇目录
进程间通信(IPC)方式二:管道(不推荐使用,了解即可),会导致数据不安全的情况出现,
由Pipe方法返回的两个连接对象表示管道的两端。每个连接对象都有send和recv方法(除其他之外)。
注意,如果两个进程(或线程)试图同时从管道的同一端读取或写入数据,那么管道中的数据可能会损坏。
当然,在使用管道的不同端部的过程中不存在损坏风险。
话不多说,直接上代码
from multiprocessing import Process, Pipe #多导入一个Pipe模块
def f1(conn):
from_zhujincheng = conn.recv() #创建管道接受,
print('我是子进程')
print('来自主进程的消息:',from_zhujincheng)
if __name__ == '__main__':
conn1,conn2 = Pipe() #创建一个管道对象,全双工,返回管道的两端,但是一端发送的消息,只能另外一端接收,自己这一端是不能接收的
#可以将一端或者两端发送给其他的进程,那么多个进程之间就可以通过这一个管道进行通信了
p1 = Process(target=f1,args=(conn2,)) #这块可以多写一个进程,试一试多进程通信
p1.start()
conn1.send('小宝贝,你在哪') #管道这一端就可以开始发送内容了 也可以用conn1再写一个
print('我是主进程')
很简单,这个平时或工作一般用的不多。
python线程的事件用于主进程控制其他进程的执行,事件主要提供了三个方法 set、wait、clear。 事件处理的机制:全局定义了一个“Flag”,如果“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞,
如果“Flag”值为True,那么event.wait 方法时便不再阻塞。
上代码
from multiprocessing import Process, Event
e = Event() #创建事件对象,这个对象的初识状态为False
print('e的状态是:',e.is_set())
print('进程运行到这里了')
e.set() #将e的状态改为True
print('e的状态是:',e.is_set())
e.clear() #将e的状态改为False
e.wait() #e这个事件对象如果值为False,就在我加wait的地方等待
print('进程过了wait')
基于事件的进程通信
import time
from multiprocessing import Process,Event
def f1(e):
time.sleep(2)
n = 100
print("子进程计算结果为",n)
e.set() #将e的状态改为True
if __name__=="__main__":
e = Event() #创建事件对象
p = Process(target = f1,args = (e,)
p.start()
print("主进程等待。。。")
e.wait() #阻塞,是false时,阻塞,等e的状态改为True时,就可以往下执行
print("还安好")
知识是活的,别学死了,大家可以试一试,这个还可以怎么用
互斥锁同时只允许一个线程更改数据,而信号量Semaphore是同时允许一定数量的线程更改数据 。 假设商场里有4个迷你唱吧,所以同时可以进去4个人,如果来了第五个人就要在外面等待,等到有人出来才能再进去玩。 实现: 信号量同步基于内部计数器,每调用一次acquire(),计数器减1;每调用一次release(),计数器加1.当计数器为0时,acquire()调用被阻塞。这是迪科斯彻(Dijkstra)信号量概念P()和V()的Python实现。信号量同步机制适用于访问像服务器这样的有限资源。 信号量与进程池的概念很像,但是要区分开,信号量涉及到加锁的概念
上代码
import time
import random
from multiprocessing import Process,Semaphore
def f1(i,s)
s.acquire() #这是锁。大家都还知道吧
print("%s男嘉宾到了"%i)
time.sleep(random.randint(1,3))
s.release() #这也是锁,记住了
if __name__=="__main__":
s = Semaphore(4) #计数器,可以一次进4个,通俗来说就是一次锁4个
for i in range(10):
p = Process(target = f1,args=(i,s)
p.start()
为什么要有进程池?进程池的概念。
在程序实际处理问题过程中,忙时会有成千上万的任务需要被执行,闲时可能只有零星任务。那么在成千上万个任务需要被执行的时候,我们就需要去创建成千上万个进程么?首先,创建进程需要消耗时间,销毁进程(空间,变量,文件信息等等的内容)也需要消耗时间。第二即便开启了成千上万的进程,操作系统也不能让他们同时执行,维护一个很大的进程列表的同时,调度的时候,还需要进行切换并且记录每个进程的执行节点,也就是记录上下文(各种变量等等乱七八糟的东西,虽然你看不到,但是操作系统都要做),这样反而会影响程序的效率。因此我们不能无限制的根据任务开启或者结束进程。就看我们上面的一些代码例子,你会发现有些程序是不是执行的时候比较慢才出结果,就是这个原因,那么我们要怎么做呢?
在这里,要给大家介绍一个进程池的概念,定义一个池子,在里面放上固定数量的进程,有需求来了,就拿一个池中的进程来处理任务,等到处理完毕,进程并不关闭,而是将进程再放回进程池中继续等待任务。如果有很多任务需要执行,池中的进程数量不够,任务就要等待之前的进程执行任务完毕归来,拿到空闲进程才能继续执行。也就是说,池中进程的数量是固定的,那么同一时间最多有固定数量的进程在运行。这样不会增加操作系统的调度难度,还节省了开闭进程的时间,也一定程度上能够实现并发效果
内容有点多,慢慢看吧
上代码
import time
from multiprocessing import Process,Pool #pool = Pool(4)这个就是进程池方法 前边变量随便定义不是非得pool
def f1(n):
time.sleep(1)
return n*n
if __name__=="__main__":
pool = Pool(4) #里面这个参数是指定进程池中有多少个进程用的,4表示4个进程,如果不传参数,默认开启的进程数一般是cpu的个数,cpu个数是看你的电脑是几核的
for i in range(10):
print("xxxx")
res = pool.apply(f1,args = (i,)) #同步方法,指的是一个一个的出结果,相当于排队一样
print(res)
import time
from multiprocessing import Process,Pool
def f1(n):
time.sleep(0.5)
# print(n)
return n*n
if __name__ == '__main__':
pool = Pool(4)
res_list = []
for i in range(10):
print('xxxx')
#异步给进程池提交任务
res = pool.apply_async(f1,args=(i,))
res_list.append(res)
# print('等待所有任务执行完')
# pool.close() #锁住进程池,意思就是不让其他的程序再往这个进程池里面提交任务了
# pool.join()
#打印结果,如果异步提交之后的结果对象
for i in res_list:
print(i.get())
# time.sleep(10)
import os
from multiprocessing import Pool, Process
def f1(n):
print('进程池里面的进程id',os.getpid())
print('>>>>',n)
return n*n
def f2(asdf):
print('>>>>>>>>>>>>>',os.getpid())
print('回调函数中的结果:',asdf)
# print('回调函数中的结果:',s.get())
if __name__ == '__main__':
pool = Pool(4)
res = pool.apply_async(f1,args=(5,),f2) #异步就是不排队了一个一个的来了,直接一次性4个4个的来。
pool.close()
pool.join()
# print(res.get())
print('主进程的进程id',os.getpid())