进程之 Process join方法其他属性与进程Queue
Process join方法 以及其他属性
在主进程运行过程中如果想并发地执行其他的任务,我们可以开启子进程,此时主进程的任务与子进程的任务分两种情况
情况一:在主进程的任务与子进程的任务彼此独立的情况下,主进程的任务先执行完毕后,主进程还需要等待子进程执行完毕,然后统一回收资源。
情况二:如果主进程的任务在执行到某一个阶段时,需要等待子进程执行完毕后才能继续执行,就需要有一种机制能够让主进程检测子进程是否运行完毕,在子进程执行完毕后才继续执行,否则一直在原地阻塞,这就是join方法的作用
join的用法:
from multiprocessing import Process
import time
import random
import os
def task():
print('%s is piaoing' %os.getpid())
time.sleep(random.randrange(1,3))
print('%s is piao end' %os.getpid())
if __name__ == '__main__':
p=Process(target=task)
p.start()
p.join() #等待p停止,才执行下一行代码
print('主')
会有很多人问有了join是不是程序就会变成穿行了呢,这个你需要明确一点,join这是让主进程等待,子进程是都在运行的,同时启动4个进程,那么四个进程都会同时执行!
from multiprocessing import Process
import time
import random
def task(name):
print('%s is piaoing' %name)
time.sleep(random.randint(1,3))
print('%s is piao end' %name)
if __name__ == '__main__':
p1=Process(target=task,args=('egon',))
p2=Process(target=task,args=('alex',))
p3=Process(target=task,args=('yuanhao',))
p4=Process(target=task,args=('wupeiqi',))
p1.start()
p2.start()
p3.start()
p4.start()
既然join是等待进程结束, 那么我像下面这样写, 进程不就又变成串行的了吗?
# 当然不是了, 必须明确:p.join()是让谁等?
# 很明显p.join()是让主线程等待p的结束,卡住的是主进程而绝非子进程p,
p1.join()
p2.join()
p3.join()
p4.join()
print('主')
上面的启动进程可以简化为
p_l=[p1,p2,p3,p4]
for p in p_l:
p.start()
for p in p_l:
p.join()
Process对象的其他属性或方法
import multiprocessing
import time
# 开启进程的 第一种方式
def hi(name, x):
print("start time", time.ctime())
print("hi %s" % name)
time.sleep(x)
print(" %s end time " % name, time.ctime())
if __name__ == '__main__':
p1 = multiprocessing.Process(target=hi, args=("alex", 3), name="alex Process") # 给进程起个名字
p2 = multiprocessing.Process(target=hi, args=("egon", 2))
p1.start()
print(p1.is_alive()) # 查看进程是否存活
print(p1.name) # 查看进程的名字 生成进程的时候可以取名字
p1.terminate() # 告诉操作系统 干死p1
p2.start()
p1.join()
p2.join()
print("主进程")
print(p1.is_alive())
守护进程
主进程创建子进程,然后将该进程设置成守护自己的进程,守护进程就好比崇祯皇帝身边的老太监,崇祯皇帝已死老太监就跟着殉葬了。
关于守护进程需要强调两点:
其一:守护进程会在主进程代码执行结束后就终止
其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic processes are not allowed to have children
如果我们有两个任务需要并发执行,那么开一个主进程和一个子进程分别去执行就ok了,如果子进程的任务在主进程任务结束后就没有存在的必要了,那么该子进程应该在开启前就被设置成守护进程。主进程代码运行结束,守护进程随即终止。
import multiprocessing
import time
# 开启进程的 第一种方式
def hi(name, x):
print("start time", time.ctime())
print("hi %s" % name)
time.sleep(x)
print(" %s end time " % name, time.ctime())
if __name__ == '__main__':
p = multiprocessing.Process(target=hi, args=("alex", 2))
p1 = multiprocessing.Process(target=hi, args=("egon", 3))
p.daemon = True
p.start()
p1.start()
time.sleep(1)
print("zhu died !", ) # 进程不会等他开的子进程结束才结束
time.sleep(0.3)
print(p.is_alive())
互斥锁
进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的,而共享带来的是竞争,竞争带来的结果就是错乱
并发运行,效率高,但竞争同一打印终端,带来了打印错乱
from multiprocessing import Process
import os,time
def work():
print('%s is running' %os.getpid())
time.sleep(2)
print('%s is done' %os.getpid())
if __name__ == '__main__':
for i in range(3):
p=Process(target=work)
p.start()
如何控制,就是加锁处理。而互斥锁的意思就是互相排斥,如果把多个进程比喻为多个人,互斥锁的工作原理就是多个人都要去争抢同一个资源:卫生间,一个人抢到卫生间后上一把锁,其他人都要等着,等到这个完成任务后释放锁,其他人才有可能有一个抢到......所以互斥锁的原理,就是把并发改成穿行,降低了效率,但保证了数据安全不错乱。
#由并发变成了串行,牺牲了运行效率,但避免了竞争
from multiprocessing import Process,Lock
import os,time
def work(lock):
lock.acquire() #加锁
print('%s is running' %os.getpid())
time.sleep(2)
print('%s is done' %os.getpid())
lock.release() #释放锁
if __name__ == '__main__':
lock=Lock()
for i in range(3):
p=Process(target=work,args=(lock,))
p.start()
模拟抢票
from multiprocessing import Process, Lock ---> # 进程锁
import time
import json
def search(name):
count = json.load(open(r"E:\第四模块\并发编程\db.json", "r"))["count"]
print("<%s>查看了剩余票数为 %s" % (name, count))
def get(name):
time.sleep(1)
count_dict = json.load(open(r"E:\学\并发编程\db.json", "r"))
if count_dict["count"] > 0:
count_dict["count"] -= 1
time.sleep(3)
print("<%s> 购票成功" % name)
json.dump(count_dict, open(r"E:\并发编程\db.json", "w"))
else:
print("%s fail !" %name)
def task(name,meux):
search(name)
with meux: # 运用了上下文管理器的方法
get(name)
if __name__ == '__main__':
# f = open(r"E:\并发编程\db.json")
meux = Lock()
for i in range(10):
p = Process(target=task, args=("路人<%s>" % i, meux))
p.start()
进程队列
进程彼此之间互相隔离,要实现进程间通信(IPC),multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的。
创建队列的类(底层就是以管道和锁定的方式实现):
Queue([maxsize]):创建共享的进程队列,Queue是多进程安全的队列,可以使用Queue实现多进程之间的数据传递。
参数介绍:
maxsize是队列中允许最大项数,省略则无大小限制。
但需要明确:
1、队列内存放的是消息而非大数据
2、队列占用的是内存空间,因而maxsize即便是无大小限制也受限于内存大小
主要方法介绍:
q.put方法用以插入数据到队列中。
q.get方法可以从队列读取并且删除一个元素。
队列的使用
from multiprocessing import Queue
q = Queue(maxsize=3)
q.put("hello word")
q.put(123)
q.put([1, 234])
print("判断队列是否满了", q.full())
q.put() 如果已经满了 再放阻塞住了
print(q.get())
print(q.get())
print(q.get()) # 如果没有数据q.get会卡住
print("判断队里是否空了", q.empty())
生产者消费者模型介绍
为什么要使用生产者消费者模型
生产者指的是生产数据的任务,消费者指的是处理数据的任务,在并发编程中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。
什么是生产者和消费者模式
生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。
这个阻塞队列就是用来给生产者和消费者解耦的。
生产者消费者模型实现
from multiprocessing import Process, Queue
import time
def producer(q):
for i in range(20):
time.sleep(0.6)
print("生产的第%s个包子" % (i + 1))
res = i + 1
q.put(res)
# q.put(None) # 不能这样 因为每一个生产者的生产效率不知道,导致有个生产者生产完了放一个None
# 这样 消费者就不吃了,但是其实另外一个生产者还有包子再生产,,队列里面有包子其实,但是消费者走了一个
def consumer(q):
while True: # while q.size()>0 不能这样 因为刚开始就是0个这样进不了循环导致消费者直接没运行
res = q.get()
if res is None: # 判断如果是none则表明生产者们都生产完了
break
time.sleep(1)
print("消费者吃的第%s包子" % res)
if __name__ == '__main__':
q = Queue()
p1 = Process(target=producer, args=(q,)) # 生产者们
p2 = Process(target=producer, args=(q,)) # 生产者们
p3 = Process(target=producer, args=(q,)) # 生产者们 3个
c1 = Process(target=consumer, args=(q,)) # 消费者们 2个
c2 = Process(target=consumer, args=(q,)) # 消费者们
p1.start() # 生产者们启动
p2.start()
p3.start()
c1.start() # 消费者们启动
c2.start()
p1.join() # 保证等待消费者们执行完毕主程序才往下走
p2.join()
p3.join()
q.put(None) # 生产完毕之后往队列里面放2 个None 因为 有两个消费者 要发两个终止信息
q.put(None)
print('主程序')
JoinableQueue([maxsize]) 的使用
这就像是一个Queue对象,但队列允许项目的使用者通知生成者项目已经被成功处理。通知进程是使用共享的信号和条件变量来实现的。
参数介绍
maxsize是队列中允许最大项数,省略则无大小限制。
方法介绍
JoinableQueue的实例p除了与Queue对象相同的方法之外还具有:
q.task_done():使用者使用此方法发出信号,表示q.get()的返回项目已经被处理。如果调用此方法的次数大于从队列中删除项目的数量,将引发ValueError异常
q.join():生产者调用此方法进行阻塞,直到队列中所有的项目均被处理。阻塞将持续到队列中的每个项目均调用q.task_done()方法为止
from multiprocessing import Process, JoinableQueue
import time
def producer(q):
for i in range(3):
time.sleep(0.6)
print("生产的第%s个包子" % (i + 1))
res = i + 1
q.put(res)
q.join() # 接收信号
def consumer(q):
while True: # while q.size()>0 不能这样 因为刚开始就是0个这样进不了循环导致消费者直接没运行
res = q.get()
time.sleep(1)
print("消费者吃的第%s包子" % res)
q.task_done() # 这个信号就是说明q这个队列已经全部取完了 结束掉q,
# 给q.join 发一个信号,如果不发送这个信号,因为生产者不是守护进程,所以主进程就会一直卡住,等着生产者结束
if __name__ == '__main__':
q = JoinableQueue()
p1 = Process(target=producer, args=(q,)) # 生产者们
p2 = Process(target=producer, args=(q,)) # 生产者们
p3 = Process(target=producer, args=(q,)) # 生产者们 3个
c1 = Process(target=consumer, args=(q,)) # 消费者们 2个
c2 = Process(target=consumer, args=(q,)) # 消费者们
c1.daemon = True # 这样设置的目的是主进程结束了 消费者没必要存活了
c2.daemon = True
p1.start() # 生产者们启动
p2.start()
p3.start()
c1.start() # 消费者们启动
c2.start()
p1.join() # 这个是等待生产者都结束,这样主进程才能结束,因为如果不等待生产者结束,
# 那么主进程一结束,消费者就死了,没有消费者了就不能取包子,于发信号了
p2.join()
p3.join()
print('主程序')
进程之 Process join方法其他属性与进程Queue的更多相关文章
- python多进程之Process
由于fork创建进程不能在windows系统上使用,所以产生了multiprocessing.Process Process可以直接实例化然后用start调用,需要指定新的进程执行的函数,用元组的方式 ...
- C#启动进程之Process
在程序设计中,我们经常会遇到要从当前的程序跳到另一个程序的设计需求.也就是当前进程创建另一个进程.C#提供了Process使得我们很方便的实现. 1.Process基本属性和方法 Id //进程的Id ...
- java 多线程之:join() 方法
join()介绍 join() 定义在java.lang.Thread中. join() 的作用:让"主线程"等待"子线程"结束之后才能继续运行.
- Day9 进程理论 开启进程的两种方式 多进程实现并发套接字 join方法 Process对象的其他属性或者方法 守护进程 操作系统介绍
操作系统简介(转自林海峰老师博客介绍) #一 操作系统的作用: 1:隐藏丑陋复杂的硬件接口,提供良好的抽象接口 2:管理.调度进程,并且将多个进程对硬件的竞争变得有序 #二 多道技术: 1.产生背景: ...
- python 并发编程 多进程 Process对象的其他属性方法 join 方法
一 Process对象的join方法 在主进程运行过程中如果想并发地执行其他的任务,我们可以开启子进程,此时主进程的任务与子进程的任务分两种情况 情况一: 在主进程的任务与子进程的任务彼此独立的情况下 ...
- 并发编程(Process对象的join方法)(
一. Process对象的join方法 在主进程运行过程中如果想并发地执行其他的任务,我们可以开启子进程,此时主进程的任务与子进程的任务分两种情况 情况一:在主进程的任务与子进程的任务彼此独立的情况下 ...
- 创建进程,join方法,进程对象相关属性和方法,僵尸进程和孤儿进程,守护进程,互斥锁
创建进程 在python中提供了一个multiprocessing模块可以帮助我们使用多进程解决问题.在multiprocessing 模块中有一个类Process. from multiproces ...
- 进程 multiprocessing Process join Lock Queue
多道技术 1.空间上的复用 多个程序公用一套计算机硬件 2.时间上的复用 cpu 切换程序+保存程序状态 1.当一个程序遇到IO操作,操作系统会剥夺该程序的cpu执行权限(提高了cpu的利用率,并且不 ...
- 主动开启进程与join方法
使用multiprocessing.Process来开启进程 import os import time from multiprocessing import Process def eat(): ...
随机推荐
- 【疯狂labview】 Xcontrol+LVoop封装练习 Toolbar
labview没有toolbar,并且没有可复用的 控件 其实项目中很需要 特别是在框架平台的搭建上, 本文以Xcontrol用PICTURE的方式实现toolbar,并用LVoop封装 废话少说 直 ...
- C++(十六) — 类中引用成员函数、命名空间的使用
1.为什么类中引用成员函数? 类将属性和方法做了封装.类是一种数据类型,也就是:固定大小内存块的别名. 类的定义是一个抽象的概念,定义时不分配内存,当用类定义对象时,才分配一个固定大小的内存块. 此时 ...
- 【Python】生成器和迭代器
l=[1,2,3,4] for n in l: print n 在看上面这段代码的时候,我们没有显式的控制列表的偏移量,就可以自动的遍历了整个列表对象.那么for 语句是怎么来遍历列表l的呢?要回答这 ...
- MongoDB架构——记得结合前面的文章看,里面的图画的很好
转自:http://www.ha97.com/4580.html 本文图片来自Ricky Ho的博文MongoDB构架(MongoDB Architecture),这是个一听就感觉很宽泛的话题,但是作 ...
- 影响wifi信号强度因素
影响WIFI信号强度因素: 1.室内错综复杂的环境,会在一定程度上导致WIFI无线信号产生多径传播现象,从而导致信号强度的不稳定性: 2.室内的人员密集程度和人员流动情况也会对WIFI信号强度产生影响 ...
- Android内存优化(二)DVM和ART的GC日志分析
相关文章 Android内存优化系列 Java虚拟机系列 前言 在Java虚拟机(三)垃圾标记算法与Java对象的生命周期这篇文章中,提到了Java虚拟机的GC日志.DVM和ART的GC日志与Java ...
- 利用Python进行文章特征提取(一)
# 文字特征提取 词库模型(bag of words) 2016年2月26,星期五 # 1.词库表示法 In [9]: # sklearn 的 CountVectorizer类能够把文档词块化(tok ...
- opencv roi resize 会导致内存拷贝产生子图像
opencv roi区域 resize之后,roi的引用已不是原图的引用,而是内存拷贝产生的子图像. http://blog.csdn.net/qianqing13579/article/detail ...
- shell 中并发执行
http://bbs.51cto.com/thread-1104907-1-1.html http://www.51testing.com/html/28/116228-238978.html htt ...
- Python之os.path
os.path模块主要用于常用路径名操作,在编程中使用频率特高 os.path常用函数 abspath(path) 返回路径名path的规范化的绝对路径 split(path) 将path分割成目录和 ...