<!doctype html>
python-多进程和多线程
1.多任务
多任务处理
定义:使得计算机可以同时处理多个任务
串行:一个任务运行完之后,再执行处理另一个任务的状态
并发:表示多个任务同时执行。但是有可能在内核是串行执行的。任务被分成了多个时间片,不断切换上下文执行。
并行:多个任务同时运行的状态
2.多进程
程序:是一个指令集合
进程:正在执行的程序;或者说当你运行程序,你就启动一个进程
-编写的代码,没有运行时,被称为程序,正在运行的代码,叫进程
并发:计算机中,操作系统轮流让各个任务交替执行,由于cpu的执行速度太快了,我们感觉就像是所有任务都在同时进行
多进程中,每个进程中所有数据(包括全局变量)都各自拥有一份,互不影响
from time import sleep
def sing():
for i in range(3):
print('正在唱歌')
dance()
sleep(1)
def dance():
print('正在跳舞')
这就是一个简单的多进程
如何创建一个多进程
程序开始运行时,首先会创建一个主进程
在主进程(父进程)下,我们可以创建新的进程(子进程),子进程依赖于主进程,如果主进程结束,程序会退出
python提供了非常好用的进程包multiprocessing,借助这个包,可以轻松完成从单进程到并发执行的转换
multiprocessing模块提供了一个Process类创建一个进程对象
from multiprocessing import Process def run(name): print("子进程进行中,name = %s"%(name)) if __name__ = "__main__": print("父进程启动") p = Process(target = run,args = ('test',)) #target表示调用对象,args表示调用对象的位置参数元组 #(注意:元组中只有一个参数时,后面要加逗号) print("子进程将要执行") p.start() print(p.name,p.pid) #p.name是子进程的名称在 p = Process(target = run,args = ('test',),name = '子进程名称') #p.pid 查看子进程的编号
if __name__ == "__main__":说明 一个python的文件有两种使用方法,第一是作为程序执行,第二是import 到其他的Python程序中被调用(模块重用)执行
因此if __name__ == "__main__":的作用就是控制这两种情况执行代码的过程,——__name__是内置变量,用于表示当前模块的名字 在if__name__ == '__main__':下的代码只有在文件作为程序直接才会被执行,而import到其他程序中是不会被执行的 在windows上,子程序会自动启动他的这个文件,而在import的时候是会执行这些语句的。注意:import时倒入整个当前。.py文件 为了避免import无限递归创建子程序,在创建子程序之前加入if __name__ =="__main__":,所以必须把创建子进程的部分用那个if判断保护起来 import的时候__name__不是__main__,就不会运行了
参数介绍
-target表示调用对象,即子程序要执行的任务
-args表示调用对象的位置参数元组,args = (1,)
-name表示子进程的名称
Process类常用方法
-p.start():启动进程,并调用该子进程中的p.run()
-p.run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类一定要实现该方法
-p.terminate() (了解) 强制终止进程p,不会进行任何清理操作
-p.is_alive():如果p任然运行,返回True.用来判断进程是否在运行
-p.join([timeout]):主进程等待p终止,timeout是可选的超时时间
p.join(timeout = 3) #三秒后终止程序
Process类常用属性:
name:当前进程实例别名,默认为Process-N,N为从1开始递增的整数;
pid:为当前实例的PID值
危险并发:
from multiprocessing import Process num = 1 def run1(): global num num += 5 print("子程序1运行中,num = %d"%(num))
def run2():
global num
num += 5
print('子程序2运行中,num = %d'%(num))if name == "main":
print("父进程启动")
p1 = Process(target = run1)
p2 = Process(target= run2)
print("子程序将要执行")
p1.start()
p2.start()
p1.join()
p2.join()
print("子程序结束")
运行结果为:子程序1运行中 6
子程序2运行中 11
通过自定义类的进程
通过类方式,可以自定义一个类,继承Process类,每次实例化这个类的时候,就等同于实例化一个进程对象
import multiprocessing
import time
class Process_(multiprocessing.Process):
def run(self):
n = 5
while n > 0:
print(n)
time.sleep(1)
n -= 1
if __name__ == "__main__":
p = Process_()
p.start()
p.join()
线程池和进程池
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor from multiprocessing import cpu_count
def task(n):
print(n)
if name == 'main':
# 进程池
p = ProcessPoolExecutor(cpu_count())
for i in range(100):
p.submit(task, i)
p.shutdown()# 线程池 t = ThreadPoolExecutor(cpu_count()) for i in range(100): t.submit(task, i) t.shutdown()
进程池
实例
from multiprocessing import Pool import random import time def work(num): print(random.random*num) time.sleep(3) if __name__ == "__main__": po = Pool(3) #定义一个进程池,最大进程数为3,默认大小为CPU核数 for i in range(10): po.apply_async(work,(i,)) po.close() #进程池关闭后不再接受新的请求 po.join() #等待po中所有子进程结束,必须放在close后面
在多进程中:主进程一般用来等待,真正的任务都在子进程中执行
multiprocessing.Pool常用函数解析:
-apply_async(func[,args[,kwds]]):使用非阻塞方式调用func(并行执行,阻塞方式必须等待上一个进程退出才能执行下一个进程),args为传递给func的参数列表,kwds为传递给func的关键字参数列表;
-apply(func[,args[,kwds]])(了解即可) 使用阻塞方式调用func
-close(): 关闭Pool,使其不在接收新的任务;
-join(): 主进程阻塞,等待子进程的退出,必须在close或terminate之后使用
进程池的应用:进程池的出现是为了有效的控制进程执行的数量,已达到系统稳定的效果
单进程
实例
from multiprocessing import Process
def run(name):
print("子进程进行中,name = %s"%(name))
if __name__ = "__main__":
print("父进程启动")
p = Process(target = run,args = ('test',))
#target表示调用对象,args表示调用对象的位置参数元组
#(注意:远足中只有一个参数时,后面要加逗号)
print("子进程将要执行")
p.start()
print(p.name,p.pid)
#p.name是子进程的名称在 p = Process(target = run,args = ('test',),name = '子进程名称')
#p.pid 查看子进程的编号