python 并发编程之多线程
一、线程概念
把进程比作车间,
车间负责把资源整合到一起,是一个资源单位,而一个车间内至少有一个流水线
流水线的工作需要电源,电源就相当于cpu
所以,进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合),而线程才是cpu上的最小执行单位。
二、线程与进程的区别
如果我们的软件是一个工厂,该工厂有多条流水线,流水线工作需要电源,电源只有一个即cpu(单核cpu)
一个车间就是一个进程,一个车间至少一条流水线(一个进程至少一个线程)
创建一个进程,就是创建一个车间(申请空间,在该空间内建至少一条流水线)
而建线程,就只是在一个车间内造一条流水线,无需申请空间,随之创建开销小
三、开启线程的两种方式
1、例:
1 # 第一种 2 # from threading import Thread 3 # import time 4 5 # def task(): 6 # print('开始') 7 # time.sleep(1) 8 # print('结束') 9 # 10 # 11 # if __name__ == '__main__': 12 # t=Thread(target=task,) # 实例化得到一个对象 13 # t.start() # 对象.start()启动线程 14 # print('主') 15 16 # 第二种,通过类继承的方式 17 # from threading import Thread 18 # import time 19 # 20 # class MyThread(Thread): 21 # def run(self): 22 # print('开始') 23 # time.sleep(1) 24 # print('结束') 25 # 26 # if __name__ == '__main__': 27 # t=MyThread() 28 # t.start() 29 # print('主')
四、线程对象join方法
1 from threading import Thread 2 3 import time 4 def task(n): 5 print('开始') 6 time.sleep(n) 7 print('结束') 8 9 10 if __name__ == '__main__': 11 t=Thread(target=task,args=(2,)) 12 t.start() 13 14 15 t1=Thread(target=task,args=(3,)) 16 t1.start() 17 18 19 t.join() # 等待子进程执行结束 20 t1.join() 21 print('主')
五、同一个线程下多个线程数据共享
```python 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('主') ```
六、线程对象及其他方法
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('主')
八、线程互斥锁
```python from threading import Thread,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全局解释器锁理论
```python
#1 python的解释器有很多,cpython,jpython,pypy(python写的解释器)
#2 python的库多,库都是基于cpython写起来的,其他解释器没有那么多的库
#3 cpython中有一个全局大锁,每条线程要执行,必须获取到这个锁
#4 为什么会有这个锁呢?python的垃圾回收机制
#5 python的多线程其实就是单线程
#6 某个线程想要执行,必须先拿到GIL,我们可以把GIL看作是“通行证”,并且在一个python进程中,GIL只有一个。拿不到通行证的线程,就不允许进入CPU执行
#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如果是计算密集型:开多进程
以上两句话,只针对与cpython解释器
# 9如果是计算密集型:开多进程
以上两句话,只针对与cpython解释器
每天逼着自己写点东西,终有一天会为自己的变化感动的。这是一个潜移默化的过程,每天坚持编编故事,自己不知不觉就会拥有故事人物的特质的。 Explicit is better than implicit.(清楚优于含糊)