1.互斥锁:
原理:将并行变成串行
精髓:局部串行,只针对共享数据修改
保护不同的数据就应该用不用的锁
1 from threading import Thread, Lock
2 import time
3
4 n = 100
5
6 def task():
7 global n
8 mutex.acquire() # 效率低了 但是数据安全了
9 temp = n
10 time.sleep(0.1) # 100个线程 都拿到了100 所以就是 100个线程100-1
11 n = temp - 1
12 mutex.release()
13
14
15 if __name__ == '__main__':
16 mutex = Lock()
17 t_l = []
18 for i in range(100):
19 t = Thread(target=task)
20 t_l.append(t)
21 t.start()
22
23 for t in t_l:
24 t.join()
25
26 print('主', n)
27 """
28 主 99 原因: 100个线程 都拿到了100 所以就是 100个线程100-1 数据不安全 效率高但是不安全
29 要将并行改为串行
30 """
31 """
32 主 0 原因:效率低了 但是数据安全了
33 """
2.GIL: global interpreter lock
python3 test.py
ps aux | grep test # linux
tasklist | findstr python # windows python.exe
运行python 会有几步:
1.会有一个进程,进程内存空间 python解释器的代码先加载到内存空间
2.test.py 内容加载到内存
3.解释执行;代码交给了python解释器
线程干活指向了python代码 python代码当作参数传给了解释器
线程拿到解释器的代码,拿着python代码当作参数,执行
垃圾回收线程运行解释器的代码
垃圾回收线程和某一个线程冲突了,数据不安全,
开多个进程,GIL就没影响了, cpython解释器垃圾回收线程定期启动一个
GIL:互斥锁,保证数据的安全 对CPython解释器,同一时间只有一个线程运行
GIL.acquire() 这样垃圾线程和线程就不会冲突了,这样回收机制就变得安全了
GIL.release()
python解释器,多线程有GIL存在,保证了一个进程下面多个线程的执行是一个一个执行的
有GIL与自动的锁的工作原理:
总结:
1.GIL 一个进程内的多个线程同一时间只能运行一个线程,垃圾回收线程是安全的
2.针对不同的数据,就应该加不同的锁,解释器级别的GIL锁,只能保护解释器级别的数据,
不能保护自己的数据,针对自己的共享数据还要加锁;
线程首先抢的是;GIL锁,之后才是mutex
官网:
结论:在Cpython解释器中,同一个进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势
GIL的存在:同一时刻,只能有一个线程在运行
多核,多进程,但进程开销大,多线程,又不能用多核 ?
cpu干计算的,多个cpu
1.如果是干计算的操作,多核省时间
2.如果干IO阻塞型操作,多核没用
程序运行:都会干计算和IO操作
四个任务:
1.1个核:开多线程 ,因为多进程能用上多核
2.多核:
计算密集型:用多进程,用多核,eg:金融行业的,计算比较多,虽然多进程开销大,但多核,保证了计算快
IO密集型:用多线程,同一时间只能用一个核,1个核一个进程,多线程就在一个核上来回切和四个核来回切是一样的
现在写的软件:
网络打交道,网络的IO
IO密集型,用多线程
1 """
2 计算密集型应该用: 多进程 效率高
3 """
4 from multiprocessing import Process
5 from threading import Thread
6 import os,time
7
8 def work():
9 res=0
10 for i in range(100000000):
11 res*=i
12
13
14 if __name__ == '__main__':
15 l=[]
16 print(os.cpu_count()) #本机为8核
17 start=time.time()
18 for i in range(8):
19 # p=Process(target=work) #耗时8s多
20 p=Thread(target=work) #耗时37s多
21 l.append(p)
22 p.start()
23 for p in l:
24 p.join()
25 stop=time.time()
26 print('run time is %s' %(stop-start))
27
28 """
29 IO密集型:多线程 效率高
30 """
31 from multiprocessing import Process
32 from threading import Thread
33 import threading
34 import os,time
35 def work():
36 time.sleep(2)
37 print('===>')
38
39 if __name__ == '__main__':
40 l=[]
41 print(os.cpu_count()) #本机为8核
42 start=time.time()
43 for i in range(400):
44 # p=Process(target=work) #耗时8s多,大部分时间耗费在创建进程上
45 p=Thread(target=work) #耗时2s多
46 l.append(p)
47 p.start()
48 for p in l:
49 p.join()
50 stop=time.time()
51 print('run time is %s' %(stop-start))
3.死锁:
你拿着我的锁,我拿着你的锁
互斥锁:Lock()
互斥锁只能acquire一次
递归锁:RLock()
可以连续acquire多次,每acquire一次计数器+1,
只有计数为0时,才能被抢到acquire
1 from threading import Thread,Lock
2 import time
3
4 mutexA=Lock()
5 mutexB=Lock()
6
7 class MyThread(Thread):
8 def run(self):
9 self.f1()
10 self.f2()
11
12 def f1(self):
13 mutexA.acquire()
14 print('%s 拿到了A锁' %self.name)
15
16 mutexB.acquire()
17 print('%s 拿到了B锁' %self.name)
18 mutexB.release()
19
20 mutexA.release()
21
22
23 def f2(self):
24 mutexB.acquire()
25 print('%s 拿到了B锁' % self.name)
26 time.sleep(0.1)
27
28 mutexA.acquire()
29 print('%s 拿到了A锁' % self.name)
30 mutexA.release()
31
32 mutexB.release()
33
34 if __name__ == '__main__':
35 for i in range(10):
36 t=MyThread()
37 t.start()
38 """
39 Thread-1 拿到了A锁 # 死锁了 卡住了
40 Thread-1 拿到了B锁
41 Thread-1 拿到了B锁
42 Thread-2 拿到了A锁
43 """
1 # 互斥锁只能acquire一次
2 # from threading import Thread,Lock
3 #
4 # mutexA=Lock()
5 #
6 # mutexA.acquire()
7 # mutexA.release()
8
9 # 递归锁:可以连续acquire多次,每acquire一次计数器+1,只有计数为0时,才能被抢到acquire
10 from threading import Thread,RLock
11 import time
12
13 mutexB=mutexA=RLock()
14
15 class MyThread(Thread):
16 def run(self):
17 self.f1()
18 self.f2()
19
20 def f1(self):
21 mutexA.acquire()
22 print('%s 拿到了A锁' %self.name)
23
24 mutexB.acquire()
25 print('%s 拿到了B锁' %self.name)
26 mutexB.release()
27
28 mutexA.release()
29
30
31 def f2(self):
32 mutexB.acquire()
33 print('%s 拿到了B锁' % self.name)
34 time.sleep(2)
35
36 mutexA.acquire()
37 print('%s 拿到了A锁' % self.name)
38 mutexA.release()
39
40 mutexB.release()
41
42 if __name__ == '__main__':
43 for i in range(10):
44 t=MyThread()
45 t.start()
46 """
47 Thread-1 拿到了A锁 # 解决了 死锁
48 Thread-1 拿到了B锁
49 Thread-1 拿到了B锁
50 Thread-1 拿到了A锁
51 Thread-2 拿到了A锁
52 Thread-2 拿到了B锁
53 Thread-2 拿到了B锁
54 Thread-2 拿到了A锁
55 Thread-4 拿到了A锁
56 Thread-4 拿到了B锁
57 Thread-5 拿到了A锁
58 Thread-5 拿到了B锁
59 Thread-5 拿到了B锁
60 Thread-5 拿到了A锁
61 Thread-7 拿到了A锁
62 Thread-7 拿到了B锁
63 Thread-7 拿到了B锁
64 Thread-7 拿到了A锁
65 Thread-9 拿到了A锁
66 Thread-9 拿到了B锁
67 Thread-9 拿到了B锁
68 Thread-9 拿到了A锁
69 Thread-3 拿到了A锁
70 Thread-3 拿到了B锁
71 Thread-3 拿到了B锁
72 Thread-3 拿到了A锁
73 Thread-6 拿到了A锁
74 Thread-6 拿到了B锁
75 Thread-6 拿到了B锁
76 Thread-6 拿到了A锁
77 Thread-10 拿到了A锁
78 Thread-10 拿到了B锁
79 Thread-10 拿到了B锁
80 Thread-10 拿到了A锁
81 Thread-8 拿到了A锁
82 Thread-8 拿到了B锁
83 Thread-8 拿到了B锁
84 Thread-8 拿到了A锁
85 Thread-4 拿到了B锁
86 Thread-4 拿到了A锁
87 """
4.信号量
信号量也是一把锁,可以指定信号量为5,对比互斥锁同一时间只能有一个任务抢到锁去执行,
信号量同一时间可以有5个任务拿到锁去执行
信号量:同一时间有多个线程在进行
1 from threading import Thread,Semaphore,currentThread
2 import time,random
3
4 sm=Semaphore(1)
5
6 def task():
7 # sm.acquire()
8 # print('%s in' %currentThread().getName())
9 # sm.release()
10 with sm: # 类似于sm.acquire() # 同一时间可以来3个人,1个人,或者2个人
11 print('%s in' %currentThread().getName())
12 time.sleep(random.randint(1,3))
13
14
15 if __name__ == '__main__':
16 for i in range(10):
17 t=Thread(target=task)
18 t.start()
19 """
20 Thread-1 in
21 Thread-2 in
22 Thread-3 in
23
24 Thread-4 in
25
26
27 Thread-6 in
28 Thread-5 in
29 Thread-7 in
30
31
32 Thread-8 in
33 Thread-9 in
34
35 Thread-10 in
36 """
5.Event:
多个线程之间同步的,一个线程告诉另一些线程可以做其他的活了
event.wait()
event.wait(2)
event.set()
event.is_set()
event.clear()
1 from threading import Thread,Event
2 import time
3
4 event=Event()
5 # event.wait() # 等 ...直到 set
6 # event.set()
7
8
9 def student(name):
10 print('学生%s 正在听课' %name)
11 # event.wait() # 学生要等7秒 才能下课
12 event.wait(2) # 学生等2秒 直接下课了
13
14 print('学生%s 课间活动' %name)
15
16
17 def teacher(name):
18 print('老师%s 正在授课' %name)
19 time.sleep(7)
20 event.set()
21
22
23 if __name__ == '__main__':
24 stu1=Thread(target=student,args=('alex',))
25 stu2=Thread(target=student,args=('wxx',))
26 stu3=Thread(target=student,args=('yxx',))
27 t1=Thread(target=teacher,args=('egon',))
28
29 stu1.start()
30 stu2.start()
31 stu3.start()
32 t1.start()
33
34
35 # ------------------
36 # 设置链接的超时时间
37 from threading import Thread,Event,currentThread
38 import time
39
40 event=Event()
41
42 def conn():
43 # print('%s is connecting'%currentThread().getName())
44 # event.wait()
45 # print('%s is connected'%currentThread().getName())
46
47 n=0
48 while not event.is_set():
49 if n == 3:
50 print('%s try too many times' %currentThread().getName())
51 return
52 print('%s try %s' %(currentThread().getName(),n))
53 event.wait(0.5)
54 n+=1
55
56 print('%s is connected' %currentThread().getName())
57
58
59 def check():
60 print('%s is checking' %currentThread().getName())
61 time.sleep(5)
62 event.set()
63
64
65 if __name__ == '__main__':
66 for i in range(3):
67 t=Thread(target=conn)
68 t.start()
69 t=Thread(target=check)
70 t.start()
71 """
72 Thread-1 try 0
73 Thread-2 try 0
74 Thread-3 try 0
75 Thread-4 is checking
76 Thread-3 try 1
77 Thread-2 try 1
78 Thread-1 try 1
79 Thread-3 try 2
80 Thread-1 try 2
81 Thread-2 try 2
82 Thread-3 try too many times
83 Thread-2 try too many times
84 Thread-1 try too many times
85 """
6.定时器:Timer
t=Timer(5,task,args=('egon',))
t.start()
t.cancel()
1 from threading import Timer
2
3 def task(name):
4 print('hello %s' %name)
5
6 t=Timer(5,task,args=('egon',)) # 就是起了一个线程
7 t.start()
8
9 # ----------------------
10 from threading import Timer
11 import random
12
13 class Code:
14 def __init__(self):
15 self.make_cache()
16
17 def make_cache(self,interval=10):
18 self.cache=self.make_code()
19 print(self.cache)
20 self.t=Timer(interval,self.make_cache)
21 self.t.start()
22
23 def make_code(self,n=4):
24 res=''
25 for i in range(n):
26 s1=str(random.randint(0,9))
27 s2=chr(random.randint(65,90))
28 res+=random.choice([s1,s2])
29 return res
30
31 def check(self):
32 while True:
33 code=input('请输入你的验证码>>: ').strip()
34 if code.upper() == self.cache:
35 print('验证码输入正确')
36 self.t.cancel()
37 break
38
39 obj=Code()
40 obj.check()