1、创建一个进程
Process(target=目标函数名, args=参数) 和 线程的接口类似。许多方法也是类似的。
from multiprocessing import Process
import time
def check(name):
time.sleep(3)
print("{}".format(name))
def age(x):
time.sleep(6)
print(x)
# 必须加上这句话,主进程
if __name__ == '__main__':
p = Process(target=check, args=('Jax',))
p1 = Process(target=age, args=(19,))
p.start()
p1.start() # 激活进程
print(p.pid) # 打印进程号
p.join() # 阻塞主进程,直到子进程结束,等待子进程的退出
p1.join()
print(p.name) # 进程名
print(p.is_alive()) # 进程是否存活
还可以通过继承的方式来实例进程对象。
from multiprocessing import Process
class MyProcess(Process):
def run(self):
print(self.name)
if __name__ == '__main__': # 必须写上,保证是主进程
p = MyProcess()
p1 = MyProcess()
p.start()
p1.start()
2、守护进程
子进程和主进程一同退出。当主进程退出时一同退出,不管子进程是否结束。如果有其中一个子进程没有设置相当于主进程仍然没有完,仍然会等待子进程结束。在进程中只能通过t.daemon = True来设置守护线程。
from multiprocessing import Process
import time
def check(name):
time.sleep(3)
print("{}".format(name))
def age(x):
time.sleep(6)
print(x)
if __name__ == '__main__':
p = Process(target=check, args=('Jax',))
p1 = Process(target=age, args=(19,))
p1.daemon=True # 设置守护进程
p.start()
p1.start()
print("23233")
3、进程的pid
当前进程的父进程是编译器
from multiprocessing import Process
import os
def check(name):
print("当前进程{}".format(os.getpid()))
print("当前父进程{}".format(os.getppid()))
print("--------------------------")
if __name__ == '__main__':
check("Jax")
p = Process(target=check, args=('Jax',))
p.start()
>>> 当前进程8492
>>> 当前父进程9908
>>> --------------------------
>>> 当前进程8460
>>> 当前父进程8492
>>> --------------------------
4、进程通信
1、Pipe()管道:multiprocessing.Pipe()用来创建管道,返回两个连接对象,代表管道的两端,一般用于进程之间的通。
recv()接收消息,接收不到会等待,卡住。send() 发消息
from multiprocessing import Process,Pipe
def Foo(conn):
print(conn.recv())
conn.send("Ok")
if __name__ == '__main__':
parent_conn,child_conn = Pipe() # 返回两个管道连接
print('---->',id(child_conn))
p = Process(target=Foo,args=(child_conn,)) # 创建进程时将一个管道给子进程
p.start()
parent_conn.send("2333")
print("收到子进程的消息"+parent_conn.recv())
>>> ----> 2765870483048
>>> 2333
>>> 收到子进程的消息Ok
2、进程队列: 进程之间都是相互独立的。
import multiprocessing
def Foo(q):
q.put(2333)
q.put('?')
if __name__ == '__main__':
# 进程队列用于进程间的通信
q = multiprocessing.Queue()
# 创建子进程时就把队列传过去
p = multiprocessing.Process(target=Foo,args=(q,))
p.start()
print(q.get())
print(q.get())
不同进程通过队列通信。传递的队列 q 是数据复制得来的。
3、基于协程处理并行:greenlet 。
switch( [参数] )方法切换执行点。
from greenlet import greenlet
def check():
print(56)
# 跳到it函数,跳转的时候会保留上下文,再次切换回来时,继续执行
gr2.switch()
print(12)
gr2.switch()
def it():
print(34)
gr1.switch()
print(89)
if __name__ == '__main__':
gr1 = greenlet(check)
gr2 = greenlet(it)
gr1.switch()
过程:先打印56再跳到 it 函数打印34在跳回12再次跳到 it 函数打印89。
4、Manager()
Python实现多进程间通信的方式有很多种,例如队列,管道等。但是这些方式只适用于多个进程都是源于同一个父进程的情况。
如果多个进程不是源于同一个父进程,只能用共享内存,信号量等方式,但是这些方式对于复杂的数据结构,例如Queue,dict,list等,使用起来比较麻烦,不够灵活。
from multiprocessing import Process,Manager
def Foo(l,d,n):
d[n] = "0"
d['2'] = "2"
l.append(n)
if __name__ == '__main__':
L = []
# 上下文打开Manger(),不用写close()方法。
with Manager() as manger: # ------------>等价于manger = Manger()
d = manger.dict() # 创建一个字典
l = manger.list() # 创建一个列表
for i in range(10):
# 把列表,字典传过去
p = Process(target=Foo,args=(l,d,i))
p.start()
L.append(p)
for p in L:
p.join()
print(d)
print(l)
>>> {2: '0', '2': '2', 3: '0', 6: '0', 1: '0', 7: '0', 0: '0', 4: '0', 5: '0', 8: '0', 9: '0'}
>>> [2, 3, 6, 1, 7, 0, 4, 5, 8, 9]
5、进程池
from multiprocessing import Process,Pool
import time
def Foo(i):
time.sleep(1)
print(i)
return "ok"
# 回调函数需要有一个参数 是子进程return回去的值
def koo(x):
print(x)
if __name__ == '__main__':
pool = Pool(5) # 最大连接数
for i in range(100):
pool.apply_async(func=Foo, args=(i,), callback=koo) # 异步进程池
# pool.apply(func=Foo, args=(i,)) # 同步进程池
pool.close() # close必须在join之前用
pool.join()
multiprocessing.pool(process = 3) 进程池,process最大连接数,不写默认电脑cpu的核数。
close() 方法:关闭pool,使其不在接受新的任务 。
执行完close后不会有新的进程加入到pool,join函数等待所有进程。
terminate() 方法:结束工作进程,不再处理未完成的任务。直接结束。join() 方法:join方法要在close或terminate之后使用
阻塞就是花时间等待一个事物的响应,非阻塞是不花时间等待先往下进行,等到有响应再进行。
非阻塞进程池:pool.apply_async(func, (args, ),callback) 。 回调函数去打印记录,需要有一个参数,是子进程return回去的值。
回调函数:某个动作或函数执行结束成功之后再去执行的方法,
阻塞进程池:pool.apply() 同步
另外一种并发模块:
concurrent.futures模块,它提供了 ThreadPoolExecutor 和 ProcessPoolExecutor 两个类,实现了对 threading 和 multiprocessing
的更高级的抽象,对编写线程池/进程池提供了直接的支持。通常直接用这个进程池。
from concurrent.futures import ThreadPoolExecutor # 线程池
import time
def conn(arg):
print(arg)
time.sleep(1)
pool = ThreadPoolExecutor(5) # 创建一个线程池大小为5
for i in range(10):
a = pool.submit(conn,i) # 调用conn方法
print(a.result(),"-------") # 打印当前的结果,如果写在这里就不再是并发,而是串行
print(a.done()) # 显示当前线程是否结束
map方法返回一个迭代器,迭代器中的回调执行返回的结果有序的。
from concurrent.futures import ThreadPoolExecutor
li = ["2333", "6666", "00000","2333", "6666", "00000","2333", "6666", "00000"]
def conn(arg):
print(arg)
return arg
pool = ThreadPoolExecutor(5)
result = pool.map(conn, li) # 此时result是个迭代器
for i in result:
print(i)
6、有关进程的概念
进程开销高于线程.
进程就是一个程序在一个数据集上的一次动态执行过程。是最小的资源单位。
程序不运行永远不是进程。进程是由程序,数据集,进程控制块组成的。
进程控制块用来记录进程外部特征,描述进程的执行变化过程,系统可以利用它来控制和管理进程。
并行和并发:
并发:是指系统具有多个任务(动作)的能力。范围大。
并行:是指系统具 同时 有多个任务(动作)的能力。同时指的是唯一的时间节点,同一时刻。
并行是并发的子集。
同步和异步:
同步:当进程执行IO操作时(等待外部数据),等就是同步。
异步:等到数据接收成功再回来处理,不等就是异步。