目录
进程:
关于进程的理解:
多任务概念:
生活中,你可能一边听歌,一边写作业;一边上网,一边吃饭... 这些都是生活中的多任务场景。 电脑也可以执行多任务,比如你可以同时打开浏览器上网,听音乐,打开pycharm编写代码......
简单的说**多任务就是同一时间运行多个程序**
单核和多核:
--单核CPU实现多任务原理:操作系统轮流让各个任务交替进行,QQ执行2us,切换到微信,再执行2us,再切换到陌陌,执行2us...。 表面是看,每个任务反复执行下去,但是CPU调度执行速度太快了,导致我们感觉所以任务都在同时执行一样。
--多核CPU实现多任务原理:真正的并行执行多任务只能在多核CPU上实现,但是由于任务数量远远多于CPU的核心数量, 所以,操作系统也会自动把很多任务调度到每个核心上执行。
实现多任务的方式:
--多进程模式
--多线程模式
--协程
进程 > 线程 > 协程
大致上来说,进程是线程的容器,是程序的实体;进程是分配空间,线程是分配时间。
进程优点:
稳定性高,一个进程崩溃了不会影响其他进程
进程缺点:
1.创建进程开销巨大
2.操作系统能同时运行的进程数目有限
在linux下可以使用fork()函数创建进程;在windows系统上可以引用multiprocessing模块,创建进程,我们可以使用multiprocessing模块中Process类创建新的进程。python里的fork()在os模块里。
进程的创建(进程间全局变量)
from multiprocessing import Process #导入模块
process = Process(target = 函数,name = 进程名,args = (给函数传递的参数))
process.start() #启动进程并执行任务
process.run() #只是执行了任务没有启动进程
process.join() #起到堵塞的作用,完成上面的任务后才可以往下进行
terminate() #终止
os模块里的getpid()可以获取当前进程号。
###举例说明
from multiprocessing import Process # 使用该模块创建进程
from time import sleep
import os
m = 1 # 不可变类型
def task1(s, name):
global m
while True:
m += 1
sleep(s)
print('这是任务1...', os.getpid(), m) # 两进程并不共享全局变量m,相当于每个进程单独拥有一份m
def task2(s, name):
global m
while True:
m += 1
sleep(s)
print('这是任务2...', os.getpid(), m)
if __name__ == '__main__':
number = 0
print(os.getpid())
# 子进程
p = Process(target=task1, name='任务1', args=(1, 'aa'))
p.start()
print(p.name) # 打印动作在主进程里
p1 = Process(target=task2, name='任务2', args=(2, 'bb'))
p1.start()
print(p1.name) # 打印动作在主进程里
输出:
7368
任务1
任务2
这是任务1... 15988 2
这是任务2... 1692 2
这是任务1... 15988 3
这是任务1... 15988 4
这是任务2... 1692 3
这是任务1... 15988 5
这是任务1... 15988 6
这是任务2... 1692 4
这是任务1... 15988 7
这是任务1... 15988 8
这是任务2... 1692 5
这是任务1... 15988 9
这是任务1... 15988 10
...
...
...
1.该输出条件没有限制,将一直输出。
2.主进程里声明了整型变量m,在子进程里的m仅共享初始化的m,值为1;而后对m的操作并不共享,说明在进程里的变量具有独立性。
自定义进程:
当父类进程里的内容不满足需求时,我们可以自定义进程。
1.继承主进程(super的使用)
2.重写run()方法
3.创建进程对象并启动(start)进程,start的调用会默认执行自定义进程里的run()函数
###举例说明
from multiprocessing import Process
from time import sleep
class MyProcess(Process): # 继承了主进程
def __init__(self,name):
super(MyProcess,self).__init__()
self.name = name
# 重写run方法
def run(self):
n = 1
while True:
sleep(1)
print('{}____自定义进程:{}'.format(n,self.name))
n += 1
if __name__ == '__main__':
p = MyProcess('小明')
p.start()
p1 = MyProcess('小红')
p1.start()
输出:
1____自定义进程:小明
1____自定义进程:小红
2____自定义进程:小明
2____自定义进程:小红
3____自定义进程:小明
3____自定义进程:小红
4____自定义进程:小明
4____自定义进程:小红
...
...
...
以上代码仅简单作一个自定义进程,不做过多解释;其中输出没有设置限制条件,故会一直执行;要注意定义进程类时继承主进程,看情况写初始化函数 __init__(),需重写run()方法。
进程池(阻塞式和非阻塞式-多进程):
当需要创建的子进程数量不多时,可以直接利用multiprocessing中的Process动态生成多个进程, 但是如果是成百甚至上千个目标时,手动的去创建进程的工作量巨大,此时就可以用到multiprocessing模块里的(进程池)Pool方法。
初始化Pool时,可以指定一个最大进程数,当有新的请求提交到Pool中时,如果池还没有满 那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到指定的最大值,那么该请求就会等待, 直到池中有进程结束,才会创建新的进程来执行。
1.进程池中的进程在创建的时候就已经分配好了进程号,任务的迭代不影响进程号的改变。
2.进程池的存活依赖于主进程,同生共死。
非阻塞式:全部添加到队列中,立刻返回,并不等待其他进程执行完毕才结束, 但是回调函数是等待任务完成之后才会调用执行。
pool = Pool(5) #创建了可容纳5个进程的进程池
pool.apply_async(func=函数名,args=(参数,),callback=回调函数名) #当函数参数只有一个,在参数后面加逗号
非阻塞式标志是apply_async;callback是回调函数的意思,等待任务完成后执行。
###举例说明
import os
import time
import random
from multiprocessing import Pool
#非阻塞式进程
def task(task_name):
print('开始做任务啦!',task_name)
start = time.time() #算出当前时间
#使用sleep()
time.sleep(random.random()*2)
end = time.time()
return '完成任务{} 用时:{},进程ID:{}'.format(task_name,end-start,os.getpid())
container = []
def callback_func(n):
container.append(n)
if __name__ == '__main__':
#创建了容量为5的进程池,在创建的时候就已经分配好了进程号,任务的迭代不影响进程号的改变
pool = Pool(5) #进程池的存活依赖于主进程,同生共死
tasks = ['LOL','洗衣服','吃饭','遛狗','听歌','睡觉']
for i in tasks:
#进程池里可装5个进程,但是有6个任务所以最后一个任务需要等其他进程结束才能开始,需要排队
pool.apply_async(func=task,args=(i,),callback=callback_func) #使用非阻塞模式(非同步);callback为回调,当func执行完毕后,return的东西会给到回调函数callback
pool.close() #添加任务结束;关闭进程池,不再接收新的请求。
pool.join() #堵住主进程,必须在完成任务后才能往下进行
for i in container:
print(i)
print('OVER!')
输出:
开始做任务啦! LOL
开始做任务啦! 洗衣服
开始做任务啦! 吃饭
开始做任务啦! 遛狗
开始做任务啦!