进程和线程的概念 - 什么是进程 / 什么是线程 /
线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。一个线程是一个execution context(执行上下文),即一个cpu执行时所需要的一串指令。 一个程序的执行实例就是一个进程。每一个进程提供执行程序所需的所有资源。(进程本质上是资源的集合)
使用进程 - fork函数 / multiprocessing模块 / 进程池 / 进程间通信
fork()
import os
pid = os.fork()
if pid = 0:
print('******' %os.getpid())
else:
print(''***' %os.getpid())
如图,if语句和else语句中打印了,这就是fork()调用,返回两次,因为操作系统自动把当前程序(父进程)复制了一份(称为子进程)分别在父进程和子进程内放回。
我们用一个变量pid来接收返回值。
子进程的返回值永远是0,这就进入了if语句,为True,打印第一句话,而父进程的返回值就是子进程的ID编号,所以进入else语句,打印第二句话。
multiprocessing模块
管理进程模块
Process(用于创建进程模块) Pool(用于创建管理进程池)
Queue(用于进程通信,资源共享) Value,Array(用于进程通信,资源共享)
Pipe(用于管道通信) Manager(用于资源共享)
同步子进程模块:
Condition Event Lock RLock Semaphore
Process模块用来创建子进程,是Multiprocessing核心模块,使用方式与Threading类似,可以实现多进程的创建,启动,关闭等操作。
一般需要传入target目标函数,args函数的参数
进程池
初始化Pool时,可以指定一个最大进程数,当有新的请求提交到Pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到指定的最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来执行,
from multiprocessing import Pool
import os,time,random
def worker(msg):
t_start = time.time()
print("%s开始执行,进程号为%d"%(msg,os.getpid()))
#random.random()随机生成0~1之间的浮点数
time.sleep(random.random()*2)
t_stop = time.time()
print(msg,"执行完毕,耗时%0.2f"%(t_stop-t_start))
po=Pool(3) #定义一个进程池,最大进程数3
for i in range(0,10):
#Pool.apply_async(要调用的目标,(传递给目标的参数元祖,))
#每次循环将会用空闲出来的子进程去调用目标
po.apply_async(worker,(i,))
print("----start----")
po.close() #关闭进程池,关闭后po不再接收新的请求
po.join() #等待po中所有子进程执行完成,必须放在close语句之后
print("-----end-----")
————————————————
版权声明:本文为CSDN博主「一人在山旁」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_38260497/article/details/87900851
常用函数:
apply_async(func[, args[, kwds]]) :使用非阻塞方式调用func(并行执行,堵塞方式必须等待上一个进程退出才能执行下一个进程),args为传递给func的参数列表,kwds为传递给func的关键字参数列表;
apply(func[, args[, kwds]]):使用阻塞方式调用func
close():关闭Pool,使其不再接受新的任务;
terminate():不管任务是否完成,立即终止;
join():主进程阻塞,等待子进程的退出, 必须在close或terminate之后使用;
进程间通信
Queue
Put方法:以插入数据到队列中,他还有两个可选参数:blocked和timeout。详情自行百度
Get方法:从队列读取并且删除一个元素。同样,他还有两个可选参数:blocked和timeout。
Pipe
Pipe常用于两个进程,两个进程分别位于管道的两端
Pipe方法返回(comm1,conn2)代表一个管道的两端,Pipe方法有duplex参数,默认True,即全双工模式,若为Flalse,conn1只负责接收信息,conn2负责发送。
使用线程 - thread模块 / threading模块 / Thread类 / Lock类 / Condition类 / 线程池
对象 | 描述 |
Thread | 表示一个执行线程的对象 |
Lock | 锁对象 |
RLock | 可重入锁对象,使单一线程可以(再次)获得已持有的锁(递归锁) |
Condition | 条件变量对象,使得一个线程等待另外一个线程满足特定的条件,比如改变状态或者某个数据值 |
Event | 条件变量的通用版本,任意数量的线程等待某个事件的发生,在该事件发生后所有的线程都将被激活 |
Semaphore | 为线程间的有限资源提供一个计数器,如果没有可用资源时会被阻塞 |
BoundedSemaphore | 于Semaphore相似,不过它不允许超过初始值 |
Timer | 于Thread类似,不过它要在运行前等待一定时间 |
Barrier | 创建一个障碍,必须达到指定数量的线程后才可以继续 |
属性 | 描述 |
Thread类属性 | |
name | 线程名 |
ident | 线程的标识符 |
daemon | 布尔值,表示这个线程是否是守护线程 |
Thread类方法 | |
__init__(group=None,target=None,name=None,args=(),kwargs={},verbose=None,daemon=None) | 实例化一个线程对象,需要一个可调用的target对象,以及参数args或者kwargs。还可以传递name和group参数。daemon的值将会设定thread.daemon的属性 |
start() | 开始执行该线程 |
run() | 定义线程的方法。(通常开发者应该在子类中重写) |
join(timeout=None) | 直至启动的线程终止之前一直挂起;除非给出了timeout(单位秒),否则一直被阻塞 |
getName() | 返回线程名(该方法已被弃用) |
setName() | 设定线程名(该方法已弃用) |
isAlive | 布尔值,表示这个线程是否还存活(驼峰式命名,python2.6版本开始已被取代) |
isDaemon() | 布尔值,表示是否是守护线程(已经弃用) |
setDaemon(布尔值) | 在线程start()之前调用,把线程的守护标识设定为指定的布尔值(已弃用) |
线程池的基类是 concurrent.futures 模块中的 Executor,Executor 提供了两个子类,即 ThreadPoolExecutor 和 ProcessPoolExecutor,其中 ThreadPoolExecutor 用于创建线程池,而 ProcessPoolExecutor 用于创建进程池。
如果使用线程池/进程池来管理并发编程,那么只要将相应的 task 函数提交给线程池/进程池,剩下的事情就由线程池/进程池来搞定。