title: python多线程 date: 2022-04-17 15:42:21 tags: python
python多线程threading
多线程的概念
进程的相信大家都听说过,而线程可以理解为比进程更小一级的概念,一个进程内至少有一个线程,如果有多个线程,那么他们就共享进程的资源,共同完成进程的任务。
使用多线程一般有两个不同的目的: 一是把程序细分成几个功能相对独立的模块,防止其中一个功能模块阻塞导致整个程序假死(GUI程序是典型) 另一个就是提高运行效率,比如多个核同时跑,或者单核里面,某个线程进行IO操作时,另一个线程可以同时执行。
相比进程,线程有以下优点
Python中的多线程threading
创建多线程有两种方法:第一种是继承treading.Tread,创建自己的线程子类;第二种是将需线程执行的函数传入线程的构造函数中,类似于multiprocessing的用法。
treading.Tread
# encoding:utf-8
import threading
import time
import random
class sleepThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
print(self.name+ ' is created!')
def run(self):
randomTime = random.randint(1,9) # 生成 1~9的随机整数
time.sleep(randomTime)
print(self.name+ ' slept for '+str(randomTime)+' seconds' )
if __name__ == '__main__':
threads = []
for i in range(5): # 创建5个进程
th = sleepThread()
threads.append(th)
th.start()
for t in threads:
t.join()
print('all threads finished')
在上面的例子中,我们编写了自己的线程类sleepThread,然后创建了5个线程,用start()启动了各个线程,start()实际上是执行了线程类的run()函数。
将需要线程执行的函数传入线程构造函数中(推荐)
功能:一个线程不断往全局变量中写入数据,另一个线程不断从全局变量中读数据,不涉及到多个线程同时修改同一个变量时会发生冲突,所以没用到线程锁threadLock
import threading
import time
def sleepThread1(threadName, alist):
for i in range(10):
alist.append(i)
time.sleep(1)
def sleepThread2(threadName, alist):
while True:
print(alist)
time.sleep(2)
if __name__ == '__main__':
gloabList = [] #全局变量,用来线程通信
th1 = threading.Thread(target=sleepThread1, args=('Thread1',gloabList))
th2 = threading.Thread(target=sleepThread2, args=('Thread2', gloabList),)
th1.start() #开启线程th1
th2.start() #开启线程th2
th1.join() #等待线程th1结束
th2.join() #等待线程th2结束
结果如下:
[0]
[0, 1, 2]
[0, 1, 2, 3, 4]
[0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
多线程是否提高了效率
常常会有人说,因为python多线程只能使用一个核,所以多线程并没有提高效率。这句话一半对一半错。 python多线程只能使用一个核这句话针对部分python解析器如CPython等是正确的。原因是python的解析器(如CPython)因为内存管理问题设计了一个GIL(全局解析锁)。GIL保证了任何时候只有一个线程执行其字节码。这就限制了同一个进程内,只有一个线程在执行字节码,也就是说无论有多个线程,都只能用一个核。
第二句话说多线程并没有提高效率?这句话可以说对也可以说错。实际上针对CPU密集型的python进程,多线程没有提高效率;而针对IO密集型的进程,多线程提高了效率。
从上面的解释我们知道,GIL是限制了多线程并发执行的一个关键因素,而GIL仅仅是限制了同一时间同一进程只能有一个线程执行字节码,执行字节码是在CPU中的,对于CPU密集型的多线程,会一直占据着CPU导致其效果跟单线程一样。
而对于IO密集型的多线程,线程的执行时间会较多地消耗在IO上,因而CPU可供多线程轮流使用。比如说我曾用python爬取几个输入法的词库的,多线程比单线程要快了好几倍,原因就是爬虫属于IO密集型的任务,线程执行字节码所需的时间很短,而把大部分时间放在了下载和存储在本地上,线程执行完字节码后会释放GIL,从而其他线程也能够执行其字节码。从而在总体上提高了下载效率。
|