一、线程理论
计算机相当于大工厂,工厂里有一个个的车间(进程),有很多人(线程)干不同的事
真正干活的是线程--》线程是cup调度的最小单位
进程是资源分配的最小单位,线程是CPU调度的最小单位。每一个进程中至少有一个线程
线程开销更小,更轻量级
二、开启线程的两种方式
1、函数式
#第一种 from threading import Thread import time def task(): print('开始') time.sleep(1) print('结束') if __name__ == '__main__': t=Thread(target=task,) # 实例化得到一个对象 t.start() # 对象.start()启动线程 print('主'
2、通过类继承方式
#第二种 from threading import Thread import time class MyThread(Thread): def run(self): print('开始') time.sleep(1) print('结束') if __name__ == '__main__': t=MyThread() t.start() print('主')
三、线程对象join方法
from threading import Thread import time def task(n): print('开始') time.sleep(n) print('结束') if __name__ == '__main__': t=Thread(target=task,args=(2,)) t.start() t1=Thread(target=task,args=(3,)) t1.start() t.join() # 等待子进程执行结束 t1.join() print('主')
四、同一个进程下多个线程数据共享
from threading import Thread import time money = 99 def task(n): global money money=n print('开始') # time.sleep(n) print('结束') if __name__ == '__main__': t = Thread(target=task, args=(2,)) t.start() t1 = Thread(target=task, args=(66,)) t1.start() t.join() t1.join() print(money) print('主')
五、线程对象及其他方法
from threading import Thread, current_thread,active_count import time def task(): print('开始') print(current_thread().name) # 线程名字 time.sleep(1) print('结束') if __name__ == '__main__': t1 = Thread(target=task,name='egon') t2 = Thread(target=task) t1.start() t2.start() print(active_count()) # 打印出3 ,开了两个线程,还有一个主线程
from threading import Thread, current_thread,active_count import time import os def task(n): print('开始') print(current_thread().name) # 线程名字 # 如果打印进程id号,会是什么 print(os.getpid()) time.sleep(n) print('结束') if __name__ == '__main__': t1 = Thread(target=task,name='egon',args=(2,)) t2 = Thread(target=task,args=(8,)) t1.start() t2.start() t1.join() print('---------',t1.is_alive()) print('---------',t2.is_alive()) # 当作线程id号 print('*********',t1.ident) print('*********',t2.ident) print(os.getpid()) print(active_count()) # 打印出3 ,开了两个线程,还有一个主线程
总结必知:
1 线程t.name t.getName() 2 当前进程下有几个线程存活active_count 3 t1.is_alive() 当前线程是否存活 4 t1.ident 当作是线程id号
六、守护线程
from threading import Thread, current_thread,active_count import time import os def task(n): print('开始') time.sleep(n) # print('-----',active_count()) print('结束') if __name__ == '__main__': t1 = Thread(target=task,name='egon',args=(10,)) # t1.daemon = True t1.setDaemon(True) t1.start() t2 = Thread(target=task,name='egon',args=(4,)) t2.start() print('主')
七、线程互斥锁
from threading import Thread,Lock # from multiprocessing import Lock import time import random money = 99 def task(n,mutex): global money # 在修改数据的时候,枷锁 mutex.acquire() temp = money time.sleep(0.1) money = temp - 1 # 修改完以后,释放锁,其它线程就能再次抢到锁 mutex.release() if __name__ == '__main__': ll=[] mutex=Lock() for i in range(10): t = Thread(target=task, args=(i,mutex)) t.start() ll.append(t) for i in ll: i.join() print(money)
八、GIL全局解释器锁理论
1 python的解释器有很多,cpython,jpython,pypy(python写的解释器)
2 python的库多,库都是基于cpython写起来的,其他解释器没有那么多的库
3 cpython中有一个全局大锁,每条线程要执行,必须获取到这个锁
4 为什么会有这个锁呢?python的垃圾回收机制
5 python的多线程其实就是单线程
6 某个线程想要执行,必须先拿到GIL,我们可以把GIL看作是“通行证”,并且在一个python进程中,GIL只有一个。拿不到通行证的线程,就不允许进入CPU执行
7 总结:cpython解释器中有一个全局锁(GIL),线程必须获取到GIL才能执行,我们开的多线程,不管有几个cpu,同一时刻,只有一个线程在执行(python的多线程,不能利用多核优势)
8 如果是io密集型操作:开多线程
9如果是计算密集型:开多进程
(8 9 这两句话,只针对与cpython解释器)
九、
---38---