文章目录
进程与线程的关系
一个进程有多个线程,进程之间变量不会共享,线程之间变量是可以共享的,往往需要加锁。进程都是在一个CPU核心里进行的,不会调用CPU的全部资源。
往往有几个CPU核心就可以创建多少个进程(当然也可以超过CPU核心数),每个进程单独占用一个CPU核心,所以多进程可以调用CPU的全部计算资源。
进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
对应比较小的计算问题使用多线程是首选的,因为初始化快速。
并行计算并不是开启的线程或进程越多越好,这受到CPU核心的制约,一般建议开启的进程数不超过CPU核心数的2倍,因为过多的话很多时间就会浪费在操作系统协调CPU资源上了。
这里有一篇综述的文章:
https://blog.csdn.net/qq_36387683/article/details/81147505
多线程的使用方法
获取当前线程
import threading
#返回当前线程
t=threading.current_thread()
print(t)
#获得这个线程的名字
t.getName()
#判断线程是否存活
t.is_alive()
创建线程
import threading
#创建一个线程
my_thread=threading.Thread()
#创建一个名称为my_tread的线程
my_thread=threading.Thread(name='my_tread')
def print_i(i):
t=threading.current_thread()
print('线程:{};任务:{}'.format(t.getName(),i))
my_thread=threading.Thread(name='my_tread',target=print_i,args=(1,))
#启动线程
my_thread.start() # 打印 i:1
进程加锁的方法
import threading
import time
#创建进程锁的方法
lock=threading.Lock()
a=0
def add1():
global a
try:
lock.acquire()#获得锁
tmp=a+1
time.sleep(0.2)#延时0.2秒,模拟写入所需时间
a=tmp
finally:
lock.release()#释放锁
print('进程:{};a:{}'.format(threading.current_thread().getName(),a))
threads=[threading.Thread(name='t{}'.format(i),target=add1) for i in range(10)]
[t.start() for t in threads]
利用Thread的派生子类实现多线程的并行计算
from threading import Thread
from queue import Queue
#创建子类
class worker(Thread):
def __init__(self, work_queue):
Thread.__init__(self)
self.work_queue =work_queue
def run(self):
while self.work_queue.empty() == False:
main_fun(self.html_queue.get())
if __name__ == '__main__':
#创建任务队列
mission_queue = Queue()
mission_queue.put(work)
# 创建n个线程类,并开启
for i in range(n):
workrobot = worker(mission_queue)
workrobot.start()
Workers.append(workrobot)
for worker in Workers:
worker.join()
多进程的使用方法
创建进程
from multiprocessing import Process
#创建一个进程
t=Process(name='my',target=fun,args=())
#t进程的名字
t.name
#判断t进程是否在工作
t.is_alive()
#开启t进程
t.start()
# 阻塞进程
t.join()
利用派生Process的子类开启进程的方法
from multiprocessing import Process
class MyProcess(Process):
def __init__(self):
Process.__init__(self)
def run(self):#run方法里写主要工作
#这里写程序要实现的代码
def main():
myp=MyProcess()
myp.start()
myp.join()
print("主进程终止")
if __name__ == '__main__':
main()
原文链接:https://blog.csdn.net/topleeyap/article/details/78981848
使用进程池Pool进行并行计算
-
此处不赘述关于进程操作的复杂内容,请读者自行查阅有关计算机操作系统的资料,在此仅介绍有关针对计算任务量巨大并可将进程放入进程池 (即Poo1类)中的数据分析情形。
-
当使用的操作对象数目不多时,还是可以直接使用Process类动态的生成多个进程的但是开启进程是要耗费系统资源的,通常CPU有几个核就开几个进程。如果进程数太多,手动限制进程数量就显得特别的繁琐,而且有些时候需要并行的任务数要远大于核数,此时进程池就能派上用场。
-
Poo1类可以提供指定数量的进程供用户调用。当有新的请求提交到Poo1中时,如果池没满,就会创建一个新的进程来执行请求。如果池满,请求就会告知先等待,直到池中有进程结束,才会创建新的进程来执行这些请求。
-
所以这种并行操作可以节约大量的时间。可以使用如下方式创建Pool类的实例对象:
Pool([processes=None[,initializer=Nonel,initargs=()[,maxtasksperchild=None]]]]) -
其中可供选择的参数作用如下:
- processes:要创建的进程数,如省略,将默认使用os.cpu_count() 的值:
- initlalizer:每个工作进程启动时要执行的可调用对象,默认为None:
- initarga;要传给initializer的参数组:
- maxtaskaperchild:工作进程在退出之前可完成的任务数,完成后用一个新的工作进程来替代原进程,以使未使用的资源被释放。
-
Pool类具有如下常用的方法:
- apply:在一个池工作进程中执行func(arge,** kwargs),然后返回结果。主进程会被阻塞直到函数执行结束;
- apply_async:异步apply,与apply用法一样,但它是非阻塞且支持结果返回进行回调,更适合并行执行工作。其func函数仅被poo1中的一个程调用:
- map:与内置map函数用法行为基本一致,它会使进程阻塞直到返回结果:
- imap:与map用法一致,返回结果为选代器:
- imap_unordered:与imap一致,但其并不保证返回结果与迭代传入的顺序一致:
- map_async:异步map,与map用法一败,但是它是非阻塞的。其func函数可在poo1中一次被多个进程调用:
- starmap:同map方法,但迭代中的元素也是可迭代的,并接受参数元组,然后进行元组拆包并将它们传送给给定的函数:
- starmap_async;异步starmap,与starmap用法一致
- close:关闭pool,使其不在接受新的任务;
- terminate:结束工作进程。不再处理未处理的任务。
- join:主进程阻塞等待子进程的退出,要在close或terminate之后使用:
pool.apply_async实现并行
from multiprocessing import Pool
def worker(arg):
#主要的代码写这里
def main():
#创建进程池
ps=Pool(5)
for i in range(10):
#res=ps.apply(worker,args=(i,)) # 同步执行
res=ps.apply_async(worker,args=(i,)) # 异步执行
# 关闭进程池,停止接受其它进程
ps.close()
# 阻塞进程
ps.join()
print("主进程终止")
res.get()#得到结果
if __name__ == '__main__':
main()
注意:
1.这里的if name == ‘main’:是必须的.
2.如果worker函数需要多个参数,可以通过tuple作为形参
原文链接:https://blog.csdn.net/topleeyap/article/details/78981848
pool.map_async实现并行
from multiprocessing import Pool
def worker(arg):
#主要的代码写这里
def main():
#创建进程池
ps=Pool(5)
res=ps.map(worker,args=range(10)) #利用多进程的map函数
# 关闭进程池,停止接受其它进程
ps.close()
# 阻塞进程
ps.join()
print("主进程终止")
res.get() #得到结果
if __name__ == '__main__':
main()
注意事项
注意:
-
上述代码在Unix/Linux或mac OS系统中运行是没有问题的。但是,在Windows系统中使用多进程模块,就必须把有关进行的代码写在if __ name == '__ main __'语句体中。
-
在Windows系统中,当使用多进程模块创建子进程时,会将整个主程序的代码重新执行一遍。如果不将相关的代码放在if name == 'main’语句体中,子进程在创建时会再次调用主程序,导致无限递归调用,最终导致程序崩溃。
-
由于每个python模块 (python文件)都包含内置的变量__name__,当运行模块被执行的时候,__name__等于当前文件名 (包含了后缀.py)。如果import到其他模块中,则 __ name __ 等于模块名称 (不包含后缀py)
-
而"__ main __ " 等于当前执行文件的名称 (包含了后缀.py)。所以当模块被直接执行时,__ name __ == ‘__ main __’ 结果为真;而当模块被import到其他模块中时, __ name __ == ‘main’ 结果为假,就不执行下面的代码。
-
简而言之:__ name__ 是当前模块名,当模块被直接运行时模块名为__main__。 当模块被直接运行时,代码将被运行,当模块是被导入时代码不被运行。
pool.apply_async和pool.map_async的区别
pool.apply_async
和pool.map_async
是multiprocessing.Pool
类中的两种不同的并行处理方法。
-
pool.apply_async
方法允许您将一个函数应用于一个参数,并在后台异步执行。它返回一个multiprocessing.pool.AsyncResult
对象,您可以使用get
方法获取函数的返回值。 -
pool.map_async
方法允许您将一个函数应用于一个可迭代的参数,并在后台异步执行。它返回一个multiprocessing.pool.MapResult
对象,您可以使用get
方法获取函数的返回值列表。
主要区别如下:
-
参数传递方式:
pool.apply_async
方法需要将参数作为元组传递给函数,而pool.map_async
方法可以直接将参数作为可迭代对象传递给函数。 -
返回值类型:
pool.apply_async
方法返回一个AsyncResult
对象,而pool.map_async
方法返回一个MapResult
对象。 -
获取结果方式:对于
pool.apply_async
,您需要使用get
方法获取函数的返回值。而对于pool.map_async
,您可以直接使用get
方法获取函数的返回值列表。
总的来说,pool.apply_async
适用于需要对单个参数进行并行处理的情况,而pool.map_async
适用于需要对一个可迭代参数进行并行处理的情况。
ool的更多用法可以参考:
https://blog.csdn.net/fcku_88/article/details/99685540
以及pool中常见问题:
https://blog.csdn.net/qq_41131535/article/details/89706178
利用process派生类并行计算的框架
from multiprocessing import Process,Queue
#特别要注意,这里的Queue对象是multiprocessing中的!!!!!!!!!!
class worker(Process):
def __init__(self, mission_queue):
Process.__init__(self)
self.mission_queue = mission_queue
def run(self):
while self.mission_queue.empty() == False:
main_fun(self.mission_queue.get())
if __name__=='__main__':
mission_queue = Queue()
mission_queue.put(work)
Workers=[]
#创建n个进程类,并开启
for i in range(n):
workrobot = worker(mission_queue)
workrobot.start()
Workers.append(workrobot)
for worker in Workers:
worker.join()
join()和close()的区别
这里的pool.close()是说关闭pool,使其不再接受新的(主进程)任务
这里的pool.join()是说:主进程阻塞后,让子进程继续运行完成,子进程运行完后,再把主进程全部关掉。
要先close再join。
官方参考文档:https://docs.python.org/3/library/multiprocessing.html