Python多进程
- 多进程就像生产者和消费者的关系一样
- 比如统计信息:一个负责打开,一个负责处理;或者一个搜索,一个爬
- 队列:先进先出 例如:queue
栈:先进后出 例如:网页(打开A里的B里的C,再返回,返回的路径是C到B再到A)
multiprocess
- multiprocessing包是Python中的多进程管理包,利用multiprocessing.Process对象来创建一个进程。
- 当某个进程终结之后,需要让主进程等待子进程,调用join()方法
- multiprocessing提供了Pipe和Queue,效率上更高。应优先考虑Pipe和Queue,避免使用Lock/Event/Semaphore/Condition等同步方式 (因为它们占据的不是用户进程的资源)。
- 多进程的共享:在多线程中,可以比较容易地共享资源,比如使用全局变量或者传递参数。但在多进程情况下,由于每个进程有自己独立的内存空间,以上方法并不合适。此时我们可以通过Array(进程列表数组共享)和Manager(进程字典列表共享)的方法来共享资源。
join
让主进程等待子进程
import multiprocessing
import os
def info(title):
print(title)
print(__name__)
print('father', os.getppid())
print('self', os.getpid())
print('--------')
if __name__ == "__main__": # 除了创建的子进程和子进程调用函数,其他的都是脚本主进程
# info('hello')
# 创建一个子进程调用函数
P = multiprocessing.Process(target=info,args=('hello python',))
P.start()
P.join() # 和多线程一样,也是等待的意思
print('hello word') # 若没有join则会独立运行
"""
结果:
hello python
__mp_main__
father 12500
self 8164
---------
hello word
"""
Lock
- 进程锁,可有可无(多个进程同时对同一文件处理时可使用)
- 作用:进程写完出去下个再进来
- RLock 活动锁
- Lock 锁不好就会锁死
# 当进程进行文件读写操作的时候(关键性操作的时候)需要使用锁..
from multiprocessing import Process,RLock
import multiprocessing
def _write(str_,lock):
print(multiprocessing.current_process().name)
# 写入文件
path = '/D:/school/python/work/http.txt'
# with 会自己帮你关掉
with lock:
# 路径 模式a:追加 # 编码模式:utf-8, gbk,gb12128
with open(path, mode='a',encoding='utf8') as f:
f.write(str_)
if __name__ == "__main__":
ps = []
# 创建一个活锁
lock = RLock()
for i in range(10):
p = Process(target=_write,args=('今天天气好晴朗\n',lock))
p.start()
ps.append(p)
for i in ps:
i.join()
pipe
- 管道,只能两个管道进行通信(队列可以多个)
import multiprocessing
def func(conn):
conn.send(['Joker is a good man'])
print('{} 发送了..'.format(multiprocessing.current_process().name))
print('{} 接受了 {}'.format(multiprocessing.current_process().name,conn.recv()))
conn.close()
if __name__ == "__main__":
conn_a,conn_b = multiprocessing.Pipe()
p1 = multiprocessing.Process(target=func,args=(conn_a,)).start()
conn_b.send([1, 2, 3, 4, 5, 6, 7]) # 发送数据给conn_a
print('main',conn_b.recv())
share
全局变量不共享
'''
全局变量不共享
1809 ['a', 'b', 'c']
1810 [1, 2, 3]
'''
# 全局变量不可以进程共享
import multiprocessing
import os
#os:获取进程PID
data = []
def List():
global data
data.append(1)
data.append(2)
data.append(3)
print('p',os.getpid(),data)
if __name__ == '__main__':
p = multiprocessing.Process(target=List,args=()).start() # 子进程
data.append('a') # 脚本主进程
data.append('b')
data.append('c')
print('main',os.getpid(),data)
queue
- 只能一个一个放(不像pipe)
- 如果想无穷放,在queue.put()前写 while 1:则循环不止
queueplus
- queue(maxsize=0)
- 设置队列的最大长度 如果不定义maxsize则默认maxsize=0也就是无穷大
- queue.qsize()
返回队列的大致大小。
注意,qsize() > 0 不保证后续的 get() 不被阻塞,qsize() < maxsize 也不保证 put() 不被阻塞。 - queue.empty()
如果队列为空,返回 True ,否则返回 False 。
如果 empty() 返回 True ,不保证后续调用的 put() 不被阻塞。
类似的,如果 empty() 返回 False ,也不保证后续调用的 get() 不被阻塞。 - queue.full()
如果队列是满的返回 True ,否则返回 False 。如果 full() 返回 True 不保证后续调用的 get() 不被阻塞。类似的,如果 full() 返回 False 也不保证后续调用的 put() 不被阻塞。 - queue.put(item,block = True,timeout = None)
将 item 放入队列。
如果可选参数 block 是 true 并且 timeout 是 None (默认),则在必要时阻塞至有空闲插槽可用。
如果 timeout 是个正数,将最多阻塞 timeout 秒,如果在这段时间没有可用的空闲插槽,将引发 Full 异常。
反之 (block 是 false),如果空闲插槽立即可用,则把 item 放入队列,否则引发 Full 异常 ( 在这种情况下,timeout 将被忽略)。 - queue_nowait(item)
相当于put(item.False) - queue.get(block=True, timeout=None)
从队列中移除并返回一个项目。
如果可选参数 block 是 true 并且 timeout 是 None (默认值),则在必要时阻塞至项目可得到。
如果 timeout 是个正数,将最多阻塞 timeout 秒,如果在这段时间内项目不能得到,将引发 Empty 异常。
反之 (block 是 false) , 如果一个项目立即可得到,则返回一个项目,否则引发 Empty 异常 (这种情况下,timeout 将被忽略)。 - queue.task_done()
表示前面排队的任务已经被完成。被队列的消费者线程使用。每个 get() 被用于获取一个任务, 后续调用 task_done() 告诉队列,该任务的处理已经完成。
如果 join() 当前正在阻塞,在所有条目都被处理后,将解除阻塞(意味着每个 put() 进队列的条目的 task_done() 都被收到)。
如果被调用的次数多于放入队列中的项目数量,将引发 ValueError 异常 。
import multiprocessing
import time
# 一定是要一个放,一个取
# maxsize 设置队列的最大长度.
queue = multiprocessing.Queue(maxsize=10)
def func1(queue):
while 1:
print('放入..')
queue.put(100,timeout=3)
def func2(queue):
while 1:
time.sleep(3)
res = queue.get()
print(res)
if __name__ == "__main__":
p1 = multiprocessing.Process(target=func1,args=(queue,))
# p2 = multiprocessing.Process(target=func2,args=(queue,))
p1.start()
# p2.start()
p1.join()
# p2.join()
进程数据共享 value
进程列表数组共 Array
- 一维下可看成列表
# 创建一个共享的列表/数组
# 当你有多个进程需要同时操作某一个数组的时候,你就应该搭建一个共享数组Array.
import multiprocessing
def func(m,i):
m[i] = 10000
def func1():
# Array 是一个对象
list_ = multiprocessing.Array('i',[1,2,3])
return list_
if __name__ == "__main__":
list_ = func1()
print(list_[:])
p1 = multiprocessing.Process(target=func,args=(list_,0))
p2 = multiprocessing.Process(target=func,args=(list_,1))
p1.start()
p2.start()
p1.join()
p2.join()
#:代表全取
print(list_[:])
进程字典列表共享 Manager
import multiprocessing
def func(mydict, mylist):
mydict["胡旺"] = "牛皮"
mydict["lalal"] = "大美女"
mylist.append(11)
mylist.append(22)
mylist.append(33)
if __name__ == "__main__":
# with multiprocessing.Manager() as MG:
# mydict=MG.dict()
# mylist=MG.list(range(5))
mydict = multiprocessing.Manager().dict()
# [0,1,2,3,4]
mylist = multiprocessing.Manager().list(range(5))
p = multiprocessing.Process(target=func, args=(mydict, mylist))
p.start()
p.join()
print(mylist)
print(mydict)
# print(list(range(5))) # 很牛逼的list
共享的有:
pipe queue array manager