async:异步的
parallelism:并行
race condition:资源竞争
out of memory:爆内存
GIL:global interpreter lock 全局解释器锁
并发:concurrency,在某个特定的时刻,只允许一条指令执行,只不过线程/任务之间会相互切换,使得宏观上几乎是支持多进程的并发执行。
并行:是指同一时刻有多条指令在多个处理器上同时执行;
一、线程、进程、协程的区别?
- 进程:是资源分配的单位,进程的切换需要的资源大,效率低。
- 线程:是操作系统调度的单位。
- 协程:又称为微线程,协程的切换只是单纯的操作cpu的上下文,资源小,效率高。
一个程序至少有一个进程,一个进程至少有一个线程。
在实现多任务时, 线程切换从系统层面远不止保存和恢复 CPU上下文这么简单。 操作系统为了程序运行的高效性每个线程都有自己缓存Cache等等数据,操作系统还会帮你做这些数据的恢复操作。 所以线程的切换非常耗性能。但是协程的切换只是单纯的操作CPU的上下文,所以一秒钟切换个上百万次系统都抗的住。
二、多线程与多进程的应用场景?
- cpu密集型的任务需要多进程。cpu密集型的任务,指会消耗大量cpu资源的任务,如:求1到10000000000的乘积,或者把一段很长的字编码后又解码。
- I/O密集型需要使用多线程,如果想要加速,优先使用多线程和ascyio,对于i/o密集型的任务大多数时间都花在i/o的等待上。因此一个线程/任务在等待i/o时,我们只需要切换线程/任务去执行其他的i/o操作就可以。
三、python并发的concurrent模块
在python 中,concurrent是用来完成并发的模块之一。concurrent库是python的内置模块之一,基于threading和multiprocessing两个模块实现的,并对二者进行了很好的封装和集成,使其拥有更加简洁易用的接口函数,无需在考虑start()、join()、lock()等问题。打开concurrent模块(默认安装位于…\Python\Python37\Lib),发现当前其仅内置了一个futures子模块,而futures子模块中,则有3个重要的.py文件,其中_base.py是最主要的模块,提供了大部分并发功能,但属于私有模块,不能被其他程序直接import,另外两个则是process和thread模块,即多进程和多线程,二者均调用_base实现主要并发接口函数。
四、多线程的实现,并获取返回值
- 方法一:多线程的运算结果是没有返回值的,所以需要把多线程的运算结果放入到队列中,然后到主线程中拿出来并进行计算。
import threading
from queue import Queue
def job(l,q):
sum=0
for i in l:
sum=sum+i
q.put(sum)
print('xxxxx')
def multithread():
q=Queue()
threads=[]
data=[[1,2,3],[2,3,4],[4,5,6],[5,6,7]]
for i in range(4):
t=threading.Thread(target=job,args=(data[i],q))
threads.append(t)
for trd in threads:
trd.start()
for trd in threads:
trd.join() #加载到主线程,等所有线程运行完后返回运行值
result=[]
while not q.empty():
#每次按照顺序拿出一个值
result.append(q.get())
print(result)
if __name__=='__main__':
multithread()
- 在python3.2开始,标准库为我们提供了concurrent.futures模块,它提供了TheadPoolEexcutor 和ProcessPoolExecutor两个类,实现了对threading和multiprocessing的进一步封装,主线程可以获取某一个线程的状态,以及返回值。当一个线程完成时,主线程能够独立知道。
from concurrent.futures import ThreadPoolExecutor
from concurrent.futures._base import as_completed
def thread_function(age):
return age+1
def run_thread_pool(target,args,max_work_count=3):
with ThreadPoolExecutor(max_workers=max_work_count) as t:
res=[t.submit(target,i) for i in args]
return res
if __name__=='__main__':
args=[1,3,4]
res=run_thread_pool(thread_function,args)
print(res)
for future in as_completed(res):
data=future.result()
print(data)
- 使用threadpoolExecutor的map获取返回值
from concurrent.futures import ThreadPoolExecutor
def thread_function(age):
return age+1
def run_thread_pool(target,args,max_work_count=3):
with ThreadPoolExecutor(max_workers=max_work_count) as t:
res=[t.submit(target,i) for i in args]
return res
def thread_function(age):
for i in age:
yield i+1
def run_thread_pool(target,args,max_work_count=6):
with ThreadPoolExecutor(max_workers=max_work_count) as t:
res=t.map(target,args)
return res
if __name__=='__main__':
args=[3,2,11]
res=run_thread_pool(thread_function,args=(args,))
for rs in res:
for j in rs:
print(j)
参考文章:https://blog.csdn.net/d1240673769/article/details/123888922
多线程和多进程使用实例
import requests
import time
import threading
import multiprocessing
def attack_work(name, num):
count = 1
while True:
if count > num:
break
url = "http://www.baidu.com/"
headers = {
"Referer": "http://www.baidu.com"
}
response = requests.get(url, headers=headers)
print("{},第 {} 次请求----\n".format(name, count))
count += 1
def timeLogger(func):
def wrapper(*args, **kwargs):
start_time = time.time()
func(*args, **kwargs)
duration = time.time() - start_time
print("function: {} took {}s.".format(func.__name__, round(duration, 3)))
return wrapper
@timeLogger
def multi_thread(m, n): # m为开启线程数,n为每个线程攻击的次数
print("######启动{}个线程进行请求,每个线程请求{}次,共进行{}次请求######\n".format(m, n, m * n))
lst = []
for i in range(m):
tname = '线程:threadid-{}'.format(i + 1)
t = threading.Thread(target=attack_work, name=tname, args=(tname, n))
t.start()
lst.append(t)
for t in lst:
t.join()
print("执行完成-----")
@timeLogger
def multi_process(m, n): # m为开启进程数,n为每个进程攻击的次数
print("######启动{}个进程进行请求,每个进程请求{}次,共进行{}次请求######\n".format(m, n, m * n))
lst = []
for i in range(m):
pname = "进程:processid-{}".format(i + 1)
p = multiprocessing.Process(target=attack_work, name=pname, args=(pname, n))
p.start()
lst.append(p)
for p in lst:
p.join()
print("执行完成-----")
if __name__ == "__main__":
#multi_thread(20, 100)
multi_process(20,100)