0%
全局解释器锁(GIL)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 0 pypy(没有全局解释器锁) cpython(99.999999%) -pypy python好多模块用不了, 1 全局解释器锁,GIL锁(cpython解释器的问题) -当年python设计的时候,还是单核,没有多核的概念 -python需要做垃圾回收(gc) -垃圾回收线程,进行垃圾回收 -设计了一个大锁(GIL锁),只有拿到这把锁的线程,才能执行 -同一时刻,在一个进程中,可以开多个线程,但是只能有一条线程在执行 -不能利用多核优势
只针对与cpython解释器(其他解释器,包括其他语言不这样) 2 如果是计算密集型:要开进程 3 如果是io密集型:要开线程
|
开启线程的两种方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| from threading import Thread import time
class MyThread(Thread): def __init__(self,a): self.a=a super().__init__() def run(self): time.sleep(1) print('我是子线程',self.a)
if __name__ == '__main__': t=MyThread('aaaaa') t.start() print('我是主线程')
|
多线程与多进程比较
开启速度比较
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| from threading import Thread import time import os from multiprocessing import Process
def task(): time.sleep(0.1) print('我是子线程')
if __name__ == '__main__':
ctime=time.time() t=Process(target=task) t.start() t.join() print('我是主线程') print(time.time()-ctime)
|
内存数据的共享问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| from threading import Thread import time import os from multiprocessing import Process
def task(): global n n=10 print(n)
if __name__ == '__main__': n=100 t=Thread(target=task) t.start() t.join() print('我是主线程') print(n)
|
Thread类的其他方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| from threading import Thread import threading import time def task():
res=threading.get_ident() print('子线程:',res) print('我是子线程')
if __name__ == '__main__': t=Thread(target=task) t1=Thread(target=task)
t.start() t1.start()
res=threading.get_ident() print('主线程:',res) ''' t.is_alive() t.getName() t.setName('lqz') threading:模块下的一些方法 res=threading.currentThread() res=threading.enumerate() res=threading.activeCount() res=threading.get_ident() '''
|
join方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
from threading import Thread import time
def task(): time.sleep(2) print('我是子线程')
if __name__ == '__main__': ll=[] for i in range(1000): t=Thread(target=task)
t.start() ll.append(t)
for i in ll: i.join()
print('我是主线程,子线程全都执行完了')
|
守护线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| from threading import Thread import time
def task(): time.sleep(2) print('我是子线程')
if __name__ == '__main__': t=Thread(target=task) t.setDaemon(True) t.start()
print('主线程执行结束')
|
同步锁(互斥锁)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
|
from threading import Thread,Lock import time import random def task_lock(lock): global n
with lock: time.sleep(random.random()) temp=n time.sleep(random.random()) temp=temp-1 n=temp
def task_no_lock():
global n time.sleep(random.random()) temp=n time.sleep(random.random()) temp=temp-1 n=temp
if __name__ == '__main__': n=10 lock=Lock() ll=[] for i in range(10): t=Thread(target=task_no_lock,args=[lock,]) t.start() ll.append(t) t.join()
print(n)
''' 互斥锁和join的区别 如果使用互斥锁:只锁临界区,只有临界区是串行,其他地方还是并发的 如果使用join,整个过程全变成串行执行 '''
|
信号量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
from threading import Thread,Semaphore
import time import random def task(sm,i): sm.acquire() print('%s:这个人在上厕所'%i) time.sleep(random.random()) print('%s:这个人拉完了'%i) sm.release()
sm=Semaphore(5) for i in range(40): t=Thread(target=task,args=[sm,i]) t.start()
|
Event事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| Event事件: 一些线程需要等到其他线程执行完成之后才能执行,类似于发射信号 比如一个线程等待另一个线程执行结束再继续执行
from threading import Thread, Event
import time import random
def girl(event): print('赵丽颖现在在结婚状态') time.sleep(1) print('赵丽颖离婚了') event.set()
def boy(i, event): print('屌丝%s:在等赵丽颖的离婚信号'%i) event.wait() print('屌丝%s号,收到了离婚信号,开始追' % i)
event = Event() t = Thread(target=girl, args=[event, ]) t.start()
for i in range(10): t1 = Thread(target=boy, args=[i, event]) t1.start()
|
总结
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| 1 GIL锁:全局解释器锁,在解释器之上的一把大锁,线程必须获得这把锁,才能执行,只针对与cpython解释器 2 GIL和线程锁有什么区别?有了GIL锁,为什么还要线程锁? -本身GIL和线程锁,都是线程级别的锁,GIL是内置的,解释器里的 -线程锁:开发者定义的 3 多核cpu: 如果是计算密集型:开进程 io密集型:开线程 4 开启线程的两种方式(对比进程) 5 进程和线程的比较 -进程id比较 -开启效率的比较 -共享变量 6 Thread类的其他方法,threading模块下的其他方法
7 线程join(等待子线程执行完成) 8 守护线程(如果主线程执行完成,子线程也结束) 9 互斥锁,同步锁:为了保证并发情况下数据安全,把对数据的操作过程变成串行,牺牲了效率,保证了数据安全 10 信号量,Event
|