进程(process)是cpu资源分配的最小单位,线程(thread)是cpu调度的最小单位。多线程和多进程的应用目的是为了提高并发。一个应用程序可以包含多个进程,而一个进程又可以包含多个线程。默认一个应用程序是单进程、单线程。
主要讲解创建进程的方法,以及实现共享的方式。
1、基本使用方法:
案例1:创建进程
frommultiprocessingimportProcess
deffoo(i):
print("hh",i)
if__name__ =='__main__':#在Windows下,此语句只能做测试用,不用在生产中用
li=[]
foriinrange(10):
p=Process(target=foo,args=(i,))
p.start()
执行结果:
进程同样有daemon和join方法,类似于线程
案例2:join() 也适用在进程中,逐个执行进程
当一个线程操作需要等待另一个线程执行完毕之后才能继续进行时,使用Join()方法。Join方法会等到使用该方法的线程结束后再执行下面的代码
frommultiprocessingimportProcess
deffoo(i):
print("hh",i)
if__name__ =='__main__':#在Windows下,此语句只能做测试用,不用在生产中用
li=[]
foriinrange(10):
p=Process(target=foo,args=(i,))
p.start()
p.join(5)#逐个执行每个进程,执行完毕后,继续往下执行
print('123')
执行结果:
2、数据共享:
进程之间默认数据不共享,比如QQ和百度就不会共享数据,可以通过一些方法实现数据共享
案例3:不共享的案例。
frommultiprocessingimportProcess
importtime
deffoo(i,arg):
arg.append(i)
print("hh",i,arg)
if__name__ =='__main__':#在Windows下,此语句只能做测试用,不用在生产中用
li=[]
foriinrange(10):
p=Process(target=foo,args=(i,li))
p.start()
执行结果:如果共享,则中括号中的数据i应该从0开始排列
案例4,利用queues,实现进程的共享
frommultiprocessingimportProcess
frommultiprocessingimportqueues#特殊的功能,实现进程之间数据共享
importmultiprocessing
deffoo(i,arg):
arg.put(i)
print("hh",i,arg.qsize())
if__name__ =='__main__':#在Windows下,此语句只能做测试用,不用在生产中用
li=queues.Queue(20,ctx=multiprocessing)
foriinrange(10):
p=Process(target=foo,args=(i,li))
p.start()
执行效果:
案例5,利用array实现数据共享
frommultiprocessingimportProcess, Array
defFoo(i,arg):
arg[i] =100+ i
foriteminarg:
print('----->',item)
print('================')
if__name__ =='__main__':
li=Array('i',10)
foriinrange(10):
p = Process(target=Foo,args=(i,li,))
p.start()
执行效果:
案例6,利用manage实现数据共享
frommultiprocessingimportProcess
frommultiprocessingimportManager
deffoo(i,arg):
arg[i] = i+100
print(arg.values())
if__name__ =='__main__':
obj=Manager()
li=obj.dict()
foriinrange(10):
p = Process(target=foo,args=(i,li,))
p.start()
p.join()#控制子进程,或者用下面的time来控制主进程不终止
# import time
# time.sleep(0.1)
执行效果:
3、进程锁、条件、事件等,同线程锁用法
案例7:进程锁:同线程锁的用法
frommultiprocessingimportProcess,Array,RLock
importtime
deffoo(i,arg,lc):
lc.acquire()
arg[]=arg[]-1
time.sleep(1)
print("say hi",arg[])
lc.release()
if__name__ =='__main__':
li=Array('i',1)
li[]=10
lock=RLock()
foriinrange(10):
p = Process(target=foo,args=(i,li,lock,))
p.start()
执行结果:
4、进程池:
进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止
案例8:apply串行的方式执行
frommultiprocessingimportPool
importtime
deffoo(arg):
time.sleep(1)
print("say hi",arg)
if__name__ =='__main__':
pool=Pool(5)
foriinrange(10):
pool.apply(func=foo,args=(i,))#串行的方式执行
print("end")
执行结果:
案例9:apply_async主进程执行完,不等子进程
frommultiprocessingimportPool
importtime
deffoo(arg):
time.sleep(1)
print("say hi",arg)
if__name__ =='__main__':
pool=Pool(5)
foriinrange(10):
# pool.apply(func=foo,args=(i,))#串行的方式执行
pool.apply_async(func=foo,args=(i,))#主进程执行完,不等子进程
print("end")
执行结果:end
案例10:teminate和close的终止方式
frommultiprocessingimportPool
importtime
deffoo(arg):
time.sleep(1)
print("say hi",arg)
if__name__ =='__main__':
pool=Pool(5)
foriinrange(10):
pool.apply_async(func=foo,args=(i,))#串行的方式执行
pool.close()#所有的任务全部执行完,进程继续执行
#pool.terminate() #执行到此,立即终止
pool.join()
5、协程:
协程是一种用户态的轻量级线程,其实可以认为是比线程更小的执行单元。利用一个线程,分解一个线程成为多个"微线程"。
协程存在的意义:线程切换从系统层面远不止 保存和恢复 CPU上下文这么简单。操作系统为了程序运行的高效性每个线程都有自己缓存Cache等等数据,操作系统还会帮你做这些数据的恢复操作。所以线程的切换非常耗性能。但是协程的切换只是单纯的操作CPU的上下文,所以一秒钟切换个上百万次系统都抗的住。协程,则只使用一个线程,在一个线程中规定某个代码块执行顺序。
协程的适用场景:当程序中存在大量不需要CPU的操作时(IO),适用于协程;
案例11:协程gevent的应用
fromgeventimportmonkey;monkey.patch_all()
importgevent
importrequests
deff(url):
print('GEt:%s'%url)
resp=requests.get(url)
data=resp.text
print("%d bytes received from %s"%(len(data),url))
gevent.joinall([
gevent.spawn(f,'https://www.python.org'),
gevent.spawn(f,'https://www.baidu.com'),
gevent.spawn(f,'https://www.cnblogs.com/'),
])
执行结果:
案例链接:https://pan.baidu.com/s/1snibPi1 密码:jh96
领取专属 10元无门槛券
私享最新 技术干货