python 进程详解
Posted 楊木木8023
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python 进程详解相关的知识,希望对你有一定的参考价值。
1、什么是进程?
进程:操作系统提供的抽象概念,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。程序是指令、数据及其组织形式的描述,进程是程序的实体。程序本身是没有生命周期的,它只是存在磁盘上的一些指令,程序一旦运行就是进程。
2、python如何实现多进程?
在python中,利用multiprocessing可以实现多进程。multiprocessing
是一个支持使用与 threading
模块类似的 API 来产生进程的包。 multiprocessing
包同时提供了本地和远程并发操作,通过使用子进程而非线程有效地绕过了 全局解释器锁。 因此,multiprocessing
模块允许程序员充分利用给定机器上的多个处理器。 它在 Unix 和 Windows 上均可运行。
3、实现多进程?
在 multiprocessing
中,通过创建一个 Process
对象然后调用它的 start()
方法来生成进程。需要说明的以下几个方法的区别:
run
():表示进程活动的方法。调用此方法仅仅执行方法,并不会产生进程;
start
():启动进程活动。这个方法每个进程对象最多只能调用一次。它会将对象的 run()
方法安排在一个单独的进程中调用。
join
([timeout])如果可选参数 timeout 是 None
(默认值),则该方法将阻塞,直到调用 join()
方法的进程终止。如果 timeout 是一个正数,它最多会阻塞 timeout 秒。请注意,如果进程终止或方法超时,则该方法返回 None
。检查进程的 exitcode
以确定它是否终止。一个进程可以被 join 多次。进程无法join自身,因为这会导致死锁。尝试在启动进程之前join进程是错误的。
"""
使用多进程导入multiprocessing中的Process;
模拟两个任务的执行,每次任务执行有暂停时间,并输出进程的ID和父ID
"""
from multiprocessing import Process
import time
import os
def task1(*args):
while True:
print("执行, ID:, PPID:".format(args[0], os.getpid(), os.getppid()))
time.sleep(args[1]) # 睡眠时间
def task2(*args):
while True:
print("执行, ID:, PPID:".format(args[0], os.getpid(), os.getppid()))
time.sleep(args[1])
if __name__ == '__main__':
print('父进程ID:', os.getpid()) # 两个子进程创建之前,先打印出父进程ID
print('------------------------')
t1 = Process(target=task1, args=('任务一', 1)) # 子进程1执行任务一
t2 = Process(target=task2, args=('任务二', 2)) # 子进程2执行任务二
t1.start() # start()方法来生成进程
t2.start()
结果:
E:\\python数据结构与算法\\day\\Scripts\\python.exe E:/python数据结构与算法/python_BB/process.py
父进程ID: 4564
------------------------
执行任务一, ID:9008, PPID:4564
执行任务二, ID:13972, PPID:4564
执行任务一, ID:9008, PPID:4564
执行任务一, ID:9008, PPID:4564
执行任务二, ID:13972, PPID:4564
执行任务一, ID:9008, PPID:4564
执行任务二, ID:13972, PPID:4564
执行任务一, ID:9008, PPID:4564
Process finished with exit code -1
4、进程池?
当需要创建的子进程数量不多时,可以直接利用multiprocessing中的Process动态成生多个进程,
但如果是上百甚至上千个目标,手动的去创建进程的工作量巨大,此时就可以用到multiprocessing模块提供的Pool方法。初始化Pool时,可以指定一个最大进程数,当有新的请求提交到Pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到指定的最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来执行。进程池主要分为阻塞式和非阻塞式。这里主要讲解阻塞式:全部添加到队列中,立刻返回,并没有等待其他的进程完毕,但是回调函数是等待任务完成之后才调用。也就是说,非阻塞式,当进程池满时,其他进程等待,一旦进程池的某一个进程结束就执行等待的进程。
from multiprocessing import Pool
import time
import os
import random
def task(task_name):
print('开始做任务啦!', task_name)
start = time.time()
time.sleep(random.random() * 2)
end = time.time()
print('完成任务:!用时:,进程id:'.format(task_name, (end - start), os.getpid()))
if __name__ == '__main__':
pool = Pool(5) # 进程池最多可以容纳5个进程
task_name = ['听音乐', '吃饭', '洗衣服', '打游戏', '散步', '看孩子', '做饭']
for i in task_name:
pool.apply_async(task, args=(i, ))
pool.close() # 向主进程添加任务结束
pool.join() # 阻塞主进程,也就是说只有子进程结束主进程才能结束
print('over!')
结果:
E:\\python数据结构与算法\\day\\Scripts\\python.exe E:/python数据结构与算法/python_BB/processpoll.py
开始做任务啦! 听音乐
开始做任务啦! 吃饭
开始做任务啦! 洗衣服
开始做任务啦! 打游戏
开始做任务啦! 散步
完成任务:洗衣服!用时:0.1972365379333496,进程id:9520
开始做任务啦! 看孩子
完成任务:散步!用时:0.30571460723876953,进程id:17224完成任务:打游戏!用时:0.30571460723876953,进程id:14588
开始做任务啦! 做饭
完成任务:听音乐!用时:1.2883315086364746,进程id:12108
完成任务:吃饭!用时:1.452604055404663,进程id:17512
完成任务:看孩子!用时:1.7680611610412598,进程id:9520
完成任务:做饭!用时:1.8028697967529297,进程id:17224
over!
Process finished with exit code 0
5、进程间通信?
Python 提供了多种实现进程间通信的机制,主要有以下 2 种:
(1) Python multiprocessing 模块下的 Queue 类,提供了多个进程之间实现通信的诸多方法;
(2) Pipe,又被称为“管道”,常用于实现 2 个进程之间的通信,这 2 个进程分别位于管道的两端。
queue:
"""
利用多进程模拟下载文件程序:
开启两个进程进行文件下载,然后再开启一个进程保存下载的文件
"""
from multiprocessing import Queue, Process
import time
import random
def download1(q, args):
for i in args:
q.put(i)
print('正在下载文件:'.format(i))
time.sleep(random.random()*2)
def download2(q, args):
for i in args:
q.put(i)
print('正在下载文件:'.format(i))
time.sleep(random.random()*2)
def savefile(q):
while True:
file = q.get()
print('文件保存成功'.format(file))
if __name__ == '__main__':
q = Queue(5) # 队列中可以保存的元素上限,只有元素取出后,才会有下一个进入
args1 = ['url1', 'url3', 'url5', 'url7']
args2 = ['url2', 'url4', 'url6']
down1 = Process(target=download1, args=(q, args1, ))
down2 = Process(target=download2, args=(q, args2, ))
save = Process(target=savefile, args=(q, ))
down1.start()
down2.start()
save.start()
down1.join()
down2.join()
save.terminate()
print('over!')
结果:
E:\\python数据结构与算法\\day\\Scripts\\python.exe E:/python数据结构与算法/python_BB/process_queue.py
正在下载文件:url2
正在下载文件:url1
文件url2保存成功
文件url1保存成功
正在下载文件:url4
文件url4保存成功
正在下载文件:url3
文件url3保存成功
正在下载文件:url5
文件url5保存成功
正在下载文件:url6
文件url6保存成功
正在下载文件:url7
文件url7保存成功
over!
Process finished with exit code 0
pipe:
使用 Pipe 实现进程通信,首先需要调用 multiprocessing.Pipe() 函数来创建一个管道。该函数的语法格式如下:
conn1, conn2 = multiprocessing.Pipe( [duplex=True] )
其中,conn1 和 conn2 分别用来接收 Pipe 函数返回的 2 个端口;duplex 参数默认为 True,表示该管道是双向的,即位于 2 个端口的进程既可以发送数据,也可以接受数据,而如果将 duplex 值设为 False,则表示管道是单向的,conn1 只能用来接收数据,而 conn2 只能用来发送数据。
其中
send(obj) | 发送一个 obj 给管道的另一端,另一端使用 recv() 方法接收。需要说明的是,该 obj 必须是可序列化的,如果该对象序列化之后超过 32MB,则很可能会引发 ValueError 异常。 |
recv() | 接收另一端通过 send() 方法发送过来的数据。 |
from multiprocessing import Pipe, Process
import time
import random
def download1(p, args):
for i in args:
p.send(i)
print('正在下载文件:'.format(i))
time.sleep(random.random()*2)
def savefile(p):
while True:
file = p.recv()
print('文件保存成功'.format(file))
if __name__ == '__main__':
p = Pipe()
args1 = ['url1', 'url3', 'url5', 'url7']
down1 = Process(target=download1, args=(p[0], args1, ))
save = Process(target=savefile, args=(p[1], ))
down1.start()
save.start()
down1.join()
save.terminate()
print('over!')
结果:
E:\\python数据结构与算法\\day\\Scripts\\python.exe E:/python数据结构与算法/python_BB/process_pipe.py
正在下载文件:url1
文件url1保存成功
正在下载文件:url3
文件url3保存成功
正在下载文件:url5
文件url5保存成功
正在下载文件:url7
文件url7保存成功
over!
Process finished with exit code 0
以上是关于python 进程详解的主要内容,如果未能解决你的问题,请参考以下文章