Python进程池及自定义进程
微信关注公众号:夜寒信息
致力于为每一位用户免费提供更优质技术帮助与资源供给,感谢支持!
这次给大家分享Python的进程池及自定义进程,由于Python基础已经讲述,不再赘述类,方法,及其他基础语法的概念。多进程在任务的执行使用非常广泛,比如Windows可以同时开很多的窗口,QQ,微信,游戏等。以后我们也会讲解多线程,多线程常用于下载,以后会有讲解。
一、进程重写
首先我们按照常规导入multiprocessing模块,同样我们使用
from multiprocessing import Process
语句来导入Process类。还记得上篇文章写的run()方法吗(Python的多进程运行)要重写进程,就要重写run()方法。
如果我们我们要自定义一个进程,那么我们就需要在创建我们自己的类时继承父类的Process方法:
class MyProcess(Process):
def run(self):
pass
这样我们便完成了进程自定义的结构,Process父类的东西都可以在我们的自定义进程内使用。我们可以使用一个例子,来给大家讲解。
假设我们创建两个进程,循环打印所传入的参数并计数,每执行一次进程加一,我们所需要实现的代码如下:
class MyProcess(Process):
def run(self):
n = 1
while True:
print('进程名:{} n的值:{}'.format(self.name, n))
n += 1
每当我们使用start()方法时,系统都会先进入Process类中找run()方法,通过run()方法来启动进程。我们再来添加一个主函数,创建两个进程对象,并将他们添加到进程中:
if __name__ == '__main__':
p1 = MyProcess(name='李诺')
p2 = MyProcess(name='夜寒')
p1.start()
p2.start()
这是我们运行程序,变发现程序按照我们的需求进行。下附完整代码:
# 进程:自定义
from multiprocessing import Process
class MyProcess(Process):
# 重写run()方法
def run(self):
n = 1
while True:
print('进程名:{} n的值:{}'.format(self.name, n))
n += 1
if __name__ == '__main__':
p1 = MyProcess(name='李诺')
p2 = MyProcess(name='夜寒')
p1.start()
p2.start()
二、进程池
下面我们进程池,当我们需要创建成百上千的进程时,仅仅手动创建则会非常麻烦,于是我们来使用进程池。我们使用
from multiprocessing import Pool
来调用进程池,使用
Pool()
方法来创建进程池,并定义最大进程数。进程池分为阻塞式和非阻塞式,我们一一讲解。
一、非阻塞式进程池
首先我们需要导入这几个库:
import os
import time
from multiprocessing import Pool
from random import random
首先我们创建一个任务。我们先传入一个任务名,我们使用random和sleep方法来模拟做任务的时间,再使用time来获得做任务的耗时使用os库来获得人物的pid和ppid。最后再返回我们做任务的结果,以下是实现的代码:
def task(task_name):
start = time.time()
time.sleep(random() * 2)
end = time.time()
return '完成{},用时:{},进程ID:{}'.format(task_name, (end-start), os.getpid())
接下来我们再创建主函数,先创建进程池,再创建一个列表,里面添加自己所需的进程。我们使用
pool.apply_async()
来将进程添加到进程池,下面附上实现代码:
if __name__ == '__main__':
pool = Pool(5)
tasks = ['听音乐', '打游戏', '洗衣服', '去散步', '去学习', '上厕所', '打代码']
for i in tasks:
pool.apply_async(task, args=(i,), callback=call_back)
pool.close()
pool.join()
print('OVER')
其中,pool.close()是表示添加任务结束,需要在添加完任务后在主进程加入此语句。进程池的运行必须要添加pool,join()方法,它可以堵住主进程,使进程池的任务全部执行完成之后才能结束主进程。进程池的运行依赖于主进程,主进程运行完进程池内的任务便会结束,所以添加pool.join(),否则添加完任务后不运行便会结束。
我们再来了解回调方法
callback
它会将进程(
task()
)的返回值接收,并传入回调函数,回调函数再进行处理。我们定义一个call_back()函数,用来充当callback的参数,实现代码如下:
def call_back(n):
print(n)
回调函数必须传入参数(上述代码中
n
)我们打印n的值也就是task()的返回值。以下是全部代码:
# 非阻塞式:全部添加到队列中,立即返回,并未等待其他进程执行完毕,但是回调函数等待任务完成后才调用
# 进程池
import os
import time
from multiprocessing import Pool
from random import random
# 非阻塞式进程
def task(task_name):
# print('开始任务:', task_name)
start = time.time()
time.sleep(random() * 2)
end = time.time()
return '完成{},用时:{},进程ID:{}'.format(task_name, (end-start), os.getpid())
def call_back(n):
print(n)
if __name__ == '__main__':
pool = Pool(5)
tasks = ['听音乐', '打游戏', '洗衣服', '去散步', '去学习', '上厕所', '打代码']
for i in tasks:
pool.apply_async(task, args=(i,), callback=call_back)
pool.close() # 添加表示任务结束
pool.join() # 堵住主进程,完成任务之后可继续执行主进程
print('OVER')
下面是执行截图:
我们添加了七个任务,但进程池只有5个空位。于是系统在添加进程时,未被添加的任务会等待,当其他任务执行完有空位后它在被添加。其中,系统在执行任务时,会从进程池中同时随机选取任务执行,可以看任务名称,不是按列表顺序执行,这便是非阻塞式进程池。
一、非阻塞式进程池
阻塞式进程池只需将
pool.apply_async()
改为
pool.apply()
即可。其中,系统在执行任务时,会按序从进程池中选取任务执行,可以看任务名称,当第一个任务未执行完时下一个任务不会被执行。这样虽然不会造成任务执行不按序而冲突,但会大大加长任务的执行时间,效率低下。以下附上实现需求的所有代码,这便是阻塞式进程池。
'''
特点:
添加一个任务执行一个任务,如果一个任务不结束,另一个任务就进不来
进程池:
pool = Pool(max) 创建进程池对象
pool.apply() 阻塞的
pool.apply_async() 非阻塞的
pool.close() 执行结束后关闭进程
pool.join() 让主进程让步
'''
import os
import time
from multiprocessing import Pool
from random import random
# 非阻塞式进程
def task(task_name):
# print('开始任务:', task_name)
start = time.time()
time.sleep(random() * 2)
end = time.time()
print('完成{},用时:{},进程ID:{}'.format(task_name, (end-start), os.getpid()))
def call_back(n):
print(n)
if __name__ == '__main__':
pool = Pool(5)
tasks = ['听音乐', '打游戏', '洗衣服', '去散步', '去学习', '上厕所', '打代码']
for i in tasks:
pool.apply(task, args=(i,))
pool.close() # 添加表示任务结束
pool.join() # 堵住主进程,完成任务之后可继续执行主进程
print('OVER')
下面是执行截图:
若有问题请关注微信公众号"夜寒信息"
微信关注公众号:夜寒信息
致力于为每一位用户免费提供更优质技术帮助与资源供给,感谢支持!