python并发编程之进程
一、进程中的名词要清楚在程序中是什么意思?
进程与程序的区别:程序仅仅只是一堆代码而已,而进程指的是程序的运行过程.
进程:一个程序在一个数据集上的一次动态执行过程.
***(需要强调的是:同一个程序执行两次,那也是两个进程)***
并发与并行
并发:是伪并行,即看起来是同时运行,单个cpu+多道技术就可以实现并发,(并行也属于并发)
并行:同时运行,只有具备多个cpu才能实现并行
同步与异步:
同步执行:一个进程在执行某个任务时,另外一个进程必须等待其执行完毕,才能继续执行。
异步执行:一个进程在执行某个任务时,另外一个进程无需等待其执行完毕,就可以继续执行,当有消息返回时,系统会通知进行处理,这样可以提高执行效率
进程的创建
multiprocessing模块介绍
multiprocess模块的功能众多:支持子进程,通信和共享数据,执行不同形式的同步,提供了process、Queue、Lock等组件。
多进程的创建
简单的两种方法:函数(直接代入运行)和用类类包装进程对象(继承)
from multiprocssing import Process
import time
#1.函数(直接代入运行)
def foo(i):
print("say hi", i )
if __name__ =="__main__":
for i in range(10):
p1 = Process(target=foo, args=(i,))
p2 = Process(target=foo, args=(i,))
p1.start()
p2.start()
#2用类来包装进程对象(Process继承)
class MyProcess(Process):
def __init__(self,arg):
super(MyProcess,self).__init__()
self.arg = arg
def run(self):
print("say hi", i)
time.sleep(1)
if __name__=="__main__":
for i in range(10):
p1 = MyProcess(i)
p2 = MyProcess(i)
p1.start() #start会自动调用run
p2.start()
daemon程序对比结果
#不加daemon守护进程
def foo(i):
'''
第一个方法:直接传入要运行的方法
:param i:
:return:
'''
print("say hi", i)
if __name__ =="__main__":
for i in range(2):
p = multiprocessing.Process(target=foo,args=(i,)) #target --要执行的方法
p.start() #start --启动进程
print("end")
#结果:
end
say hi 0
say hi 1
=========================================================================================
#加daemon守护进程
def foo(i):
'''
第一个方法:直接传入要运行的方法
:param i:
:return:
'''
print("say hi", i)
if __name__ =="__main__":
for i in range(10):
p = multiprocessing.Process(target=foo,args=(i,)) #target --要执行的方法
p.daemon = True #守护进程
p.start() #start --启动进程
print("end")
#结果:
end 注: 因子进程设置了daemon属性,主进程结束,它们就随着结束了
=========================================================================================
#加daemon守护进程并做修改
def foo(i):
'''
第一个方法:直接传入要运行的方法
:param i:
:return:
'''
print("say hi", i)
if __name__ =="__main__":
for i in range(2):
p = multiprocessing.Process(target=foo,args=(i,)) #target --要执行的方法
p.daemon = True #守护进程
p.start() #start --启动进程
p.join() #join()方法可以等待子进程结束后再继续往下运行
print("end")
#结果:
say hi 0
say hi 1
end
进程(锁)
进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题,竞争带来的结果就是错乱,如何控制,就是加锁处理
import multiprocessing
import sys
def worker_with(lock, f):
with lock: # #with Lock的作用相当于自动获取和释放锁(资源)
fs = open(f, 'a+')
n = 10
while n > 1:
fs.write("Lockd acquired via with\n")
n -= 1
fs.close()
'''
with lock 和 lock.acquire()与lock.release()等价的
'''
def worker_no_with(lock, f):
lock.acquire()
try:
fs = open(f, 'a+')
n = 10
while n > 1:
fs.write("Lock acquired directly\n")
n -= 1
fs.close()
finally:
lock.release()
if __name__ == "__main__":
lock = multiprocessing.Lock()
f = "file.txt"
w = multiprocessing.Process(target=worker_with, args=(lock, f))
nw = multiprocessing.Process(target=worker_no_with, args=(lock, f))
w.start()
nw.start()
print("end")
进程池:
#一:使用进程池(非阻塞,apply_async)
#coding: utf-8
from multiprocessing import Process,Pool
import time
def func(msg):
print( "msg:", msg)
time.sleep(1)
return msg
if __name__ == "__main__":
pool = Pool(processes = 3)
res_l=[]
for i in range(10):
msg = "hello %d" %(i)
res=pool.apply_async(func, (msg, )) #维持执行的进程总数为processes,当一个进程执行完毕后会添加新的进程进去
res_l.append(res)
print("==============================>") #没有后面的join,或get,则程序整体结束,进程池中的任务还没来得及全部执行完也都跟着主进程一起结束了
pool.close() #关闭进程池,防止进一步操作。如果所有操作持续挂起,它们将在工作进程终止前完成
pool.join() #调用join之前,先调用close函数,否则会出错。执行完close后不会有新的进程加入到pool,join函数等待所有子进程结束
print(res_l) #看到的是<multiprocessing.pool.ApplyResult object at 0x10357c4e0>对象组成的列表,而非最终的结果,但这一步是在join后执行的,证明结果已经计算完毕,剩下的事情就是调用每个对象下的get方法去获取结果
for i in res_l:
print(i.get()) #使用get来获取apply_aync的结果,如果是apply,则没有get方法,因为apply是同步执行,立刻获取结果,也根本无需get
#二:使用进程池(阻塞,apply)
#coding: utf-8
from multiprocessing import Process,Pool
import time
def func(msg):
print( "msg:", msg)
time.sleep(0.1)
return msg
if __name__ == "__main__":
pool = Pool(processes = 3)
res_l=[]
for i in range(10):
msg = "hello %d" %(i)
res=pool.apply(func, (msg, )) #维持执行的进程总数为processes,当一个进程执行完毕后会添加新的进程进去
res_l.append(res) #同步执行,即执行完一个拿到结果,再去执行另外一个
print("==============================>")
pool.close()
pool.join() #调用join之前,先调用close函数,否则会出错。执行完close后不会有新的进程加入到pool,join函数等待所有子进程结束
print(res_l) #看到的就是最终的结果组成的列表
for i in res_l: #apply是同步的,所以直接得到结果,没有get()方法
print(i)
详解:apply_async与apply
详解:apply_async与apply