线程是指进程内的一个执行单元,也是进程内的可调度实体.
与进程的区别:
(1) 地址空间:进程内的一个执行单元;进程至少有一个线程;它们共享进程的地址空间;而进程有自己独立的地址空间;
(2) 资源拥有:进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源
(3) 线程是处理器调度的基本单位,但进程不是.
(4) 二者均可并发执行.
简而言之,一个程序至少有一个进程,一个进程至少有一个线程.
线程的切换开销小于进程,使得多线程程序的并发性高。
另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
我们知道 *** 作系统在线程等待IO(内存、磁盘读写)的时候,会阻塞当前线程,切换到其它线程,这样在当前线程等待IO的过程中,其它线程可以继续执行。当系统线程较少的时候没有什么问题,但是当线程数量非常多的时候,却产生了问题。一是系统线程会占用非常多的内存空间,二是过多的线程切换会占用大量的系统时间。
协程刚好可以解决上述2个问题。协程运行在线程之上,当一个协程执行完成后,可以选择主动让出,让另一个协程运行在当前线程之上。协程并没有增加线程数量,只是在线程的基础之上通过分时复用的方式运行多个协程,而且协程的切换在用户态完成,切换的代价比线程从用户态到内核态的代价小很多。
它们之间的关系 并发类型- CPU密集型
在运行时比较多使用CPU进行计算和处理
如:下载数据,压缩解压 - I/O密集型
在运行时比较多使用I/O(磁盘/内存)读写
如:爬取信息,导入数据库
据统计Python比C++慢200倍,导致现在大部分大型企业依旧使用C/C++或Java
速度慢原因-
原因1:
Python是动态类型语言,边执行边解释 -
原因2:
存在GIL,无法使用多核CPU并发并行执行
GIL(Global Interpreter Lock,全局解释器锁)
是计算机程序语言解释器用于同步线程的一种机制,它使得任何时刻仅有一个线程在执行(无法使用多核并发)。
上图说 当线程在运行时它使用了GIL,当遇到I/O时释放GIL。
Thread1 获取到GIL并运行,直到遇到I/O,Thread1释放GIL。Thread2获取到GIL并运行,直到遇到I/O,Thread2释放GIL。Thread3获取到GIL并运行,直到遇到I/O,Thread3释放GIL。
同一时刻,只能有一个线程在运行。由于Python有GIL的存在,即使电脑有多核CPU,单个时刻只能使用一个1个。
相比并发加速的C++/JAVA慢的多。
GIL是为了解决多线程之前数据完整性和状态同步问题。
案列:Python中对象的管理,是使用计数器进行的,引用数为0时则释放对象。
假设:线程1和线程2都引用对象obj,obj.ref_num = 2,线程1和线程2都想要释放obj的引用。
线程1将num自减后,num值为1,切换到线程2,并进行自减,num为0,此时线程2判断num值为0,则释放obj的引用。
当切换到线程2时,由于obj的引用已经被释放,线程2无法获取num,就会报错。或者线程2可能将其他对象给释放,导致内存混乱。
- 在I/O密集期,多线程threading在I/O期间会释放GIL,实现I/O和CPU并行。
- 使用multiprocessing模块多进程,可利用多核CPU并发运行,可加快CPU密集的处理。
针对博客园网站进行网站请求,以单线程与多线程运行时间进行比较:
页数:50页
电脑配置:6核12线程
单线程花费:8.815296173095703s
多线程花费:0.45113587379455566s
粗略的算了算有19倍
import requests import threading import time urls =[ f"https://www.cnblogs.com/#p{page}" for page in range(1,50+1) ] #请求网页 def craw(u1): re = requests.get(u1) print(re.url,len(re.text)) # 单线程请求 def singleCatch(): print("******singleCatch Start*******") for i in urls: craw(i) print("******singleCatch End*******") # 多线程请求 def ThreadCatch(): print("******ThreadCatch Start*******") threads=[] for i in urls: threads.append( threading.Thread(target=craw,args=(i,)) #给craw函数传参,使用args=(x,y) ) #启动多线程 for thread in threads: thread.start() #等待多线程停止 for thread in threads: thread.join() print("******ThreadCatch End*******") if __name__ == "__main__": start = time.time() singleCatch() end = time.time() print("singleCatch time is:",end-start) start = time.time() ThreadCatch() end = time.time() print("ThreadCatch time is:",end-start)
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)