开启进程
步骤
- 创建函数
- 创建进程对象,并在target指定函数名
- 开启进程
示例代码
import multiprocessing
import time
def work1():
for i in range(50):
print('正在扫地---', i)
time.sleep(1)
def work2():
for i in range(50):
print('正在搬砖---', i)
time.sleep(1)
def main():
"""测试进程的基本使用"""
# 创建进程对象
p1 = multiprocessing.Process(target=work1)
# 开启进程
p1.start()
# 创建进程对象
p2 = multiprocessing.Process(target=work2)
# 开启进程
p2.start()
if __name__ == '__main__':
main()
进程号操作
Linux查看正在运行的进程:
ps aux
Linux查看正在运行指定进程
杀死进程
kill 进程号
程序中查看进程号
os.getpid()
程序中出看父进程号
os.getppid()
进程的执行顺序
- 子进程代码执行结束后会自动销毁
- 当所有的子进程结束,主进程才会结束
- 当主进程结束,所有的子进程会同时结束
- ==进程的执行是无序的==
进程间传参
- 在定义子进程对象时,可以指定args或者kwargs为子进程传参
- args 是一个元组
- kwargs 是一个字典
示例代码
import multiprocessing
def work1(text, who='扫地僧'):
for i in range(200):
print('正在----',text, '---', who ,'---',i)
open('02-UDP聊天器-多任务版.py').read()
def main():
"""验证进程的执行顺序
"""
# 创建进程
p1 = multiprocessing.Process(target=work1, args=('扫地',), kwargs={'who':'乔峰'})
# 开启进程
p1.start()
p2 = multiprocessing.Process(target=work1, args=('搬砖',))
p2.start()
if __name__ == '__main__':
main()
进程间通信
因为主进程开启子进程时,会把主进程当前所有资源复制一份,并且主进程从上往下顺序执行,而子进程从指定的函数开始执行,所以==进程之间是没发共享数据的==,如果需要进程间==共享数据则需要用到Queue==
Queue(消息队列),遵循先进先出,每次get()时候都会获取当前队列中第一个元素,并且该元素会从队列中移除
Queue基本使用
- 创建一个Queue,q = multiprocessing.Queue()
- 向队列写数据 q.put(“”)
- 从队里读数据 q.get()
示例代码
import multiprocessing
def work1(q):
"""向消息队列写入数据"""
for i in range(5000):
q.put('数据%d' % i)
print('数据放入结束')
def work2(q):
"""从队列取出数据"""
while True:
print('work2--取出', q.get())
def main():
"""测试进程间通信"""
q = multiprocessing.Queue()
p1 = multiprocessing.Process(target=work1, args=(q,))
p1.start()
# p1.join()
p2 = multiprocessing.Process(target=work2, args=(q,))
p2.start()
if __name__ == '__main__':
main()
Queue常见方法说明
初始化Queue()对象时(例如:q=Queue()),若括号中没有指定最大可接收的消息数量,或数量为负值,那么就代表可接受的消息数量没有上限(直到内存的尽头);
* Queue.qsize():返回当前队列包含的消息数量;
- Queue.empty():如果队列为空,返回True,反之False ;
- Queue.full():如果队列满了,返回True,反之False;
- Queue.get([block[, timeout]]):获取队列中的一条消息,然后将其从列队中移除,block默认值为True;
1)如果block使用默认值,且没有设置timeout(单位秒),消息列队如果为空,此时程序将被阻塞(停在读取状态),直到从消息列队读到消息为止,如果设置了timeout,则会等待timeout秒,若还没读取到任何消息,则抛出”Queue.Empty”异常;
2)如果block值为False,消息列队如果为空,则会立刻抛出”Queue.Empty”异常;
Queue.get_nowait():相当Queue.get(False);
Queue.put(item,[block[, timeout]]):将item消息写入队列,block默认值为True;
1)如果block使用默认值,且没有设置timeout(单位秒),消息列队如果已经没有空间可写入,此时程序将被阻塞(停在写入状态),直到从消息列队腾出空间为止,如果设置了timeout,则会等待timeout秒,若还没空间,则抛出”Queue.Full”异常;
2)如果block值为False,消息列队如果没有空间可写入,则会立刻抛出”Queue.Full”异常;
- Queue.put_nowait(item):相当Queue.put(item, False);
进程池
基本使用
- multiprocessing.Pool(3)#定义一个进程池,最大进程数3
- Pool().apply_async(要调用的目标,(传递给目标的参数元祖,))
- po.close() #关闭进程池,关闭后po不再接收新的请求
- po.join() #等待po中所有子进程执行完成,必须放在close语句之后
示例代码
import multiprocessing
import os
import time
def work1(i):
print('这是第 %d 个任务,使用的进程为 %d' % (i, os.getpid()))
time.sleep(1)
def main():
"""测试进程池的使用"""
# 创建进程池
pool = multiprocessing.Pool(3)
# 向进程池里放入任务
for i in range(10):
pool.apply_async(work1, (i,))
# 默认情况下,主进程不会等待进程池执行结束
pool.close() # join 之前必须调用 close
pool.join() # join 可以让主进程等待进程池执行结束
if __name__ == '__main__':
main()
进程池通信
进程池使用Queue必须要用 q = Manager().Queue()
进程线程区别
进程:1>系统进行资源分配和调度的一个独立单元
2>进程间不共享全局变量,需要进行进程间的通信
3>进程在运行过程中为独立的内存单元
线程: 1>进程的一个实体,是CPU调度和分派的基本单位
2>同时对一个全局变量进行修改,容易混乱(不一定执行完就换线程)
3>线程依赖进程的存在,线程并发性高,占用资源比进程少
4>多线程共享非全局变量不用加锁
5>多线程到同一个函数里执行,函数里的变量各是各的