先上个例子:

  1. import threading
  2. def run():
  3. for i in range(100):
  4. print(threading.current_thread().name+"--------"+str(i))
  5. print(threading.current_thread().name)
  6. t1=threading.Thread(target=run,name="线程1")
  7. t2=threading.Thread(target=run,name="线程2")
  8. t1.start()
  9. # 立马执行t1, 权限高于主线程,执行完才会执行其他的线程
  10. #t1.join()
  11. t2.start()

线程间的通信:

将变量global即可

线程锁:

  1. #一个线程上锁,只有释放锁后,其他的线程才有执行权
  2. lock=threading.Lock()
  3. def run():
  4. lock.acquire()
  5. ...
  6. lock.release()

多线程之间数据不共享:

  1. '''
  2. Python提供了 threading.local 类,将这个类实例化得到一个全局对象,
  3. 但是不同的线程使用这个对象存储的数据其它线程不可见
  4. (本质上就是不同的线程使用这个对象时为其创建一个独立的字典)。
  5. '''
  6. #tips:存取值不要在主线程中进行,否则子线程访问不到属性
  7. import threading
  8. import time
  9. a = threading.local()#全局对象
  10. def worker():
  11. a.x = 0
  12. for i in range(100):
  13. time.sleep(0.0001)
  14. a.x += 1
  15. print(threading.current_thread(),a.x)
  16. for i in range(10):
  17. threading.Thread(target=worker).start()

线程调度:

  • acquire()/release():获得/释放 Lock
  • wait([timeout]):线程挂起,直到收到一个notify通知或者超时(可选的,浮点数,单位是秒s)才会被唤醒继续运行。wait()必须在已获得Lock前提下才能调用,否则会触发RuntimeError。调用wait()会释放Lock,直至该线程被Notify()、NotifyAll()或者超时线程又重新获得Lock.
  • notify(n=1):通知其他线程,那些挂起的线程接到这个通知之后会开始运行,默认是通知一个正等待该condition的线程,最多则唤醒n个等待的线程。notify()必须在已获得Lock前提下才能调用,否则会触发RuntimeError。notify()不会主动释放Lock。
  • notifyAll(): 如果wait状态线程比较多,notifyAll的作用就是通知所有线程(这个一般用得少)
  1. '''
  2. 现在写个捉迷藏的游戏来具体介绍threading.Condition的基本使用。
  3. 假设这个游戏由两个人来玩,一个藏(Hider),一个找(Seeker)。
  4. 游戏的规则如下:
  5. 1. 游戏开始之后,Seeker先把自己眼睛蒙上,蒙上眼睛后,就通知Hider;
  6. 2. Hider接收通知后开始找地方将自己藏起来,藏好之后,再通知Seeker可以找了;
  7. 3. Seeker接收到通知之后,就开始找Hider。Hider和Seeker都是独立的个体,
  8. 在程序中用两个独立的线程来表示,在游戏过程中,两者之间的行为有一定的
  9. 时序关系,我们通过Condition来控制这种时序关系。
  10. '''
  11. import threading, time
  12. def Seeker(cond, name):
  13. time.sleep(2)
  14. cond.acquire()
  15. print('%s :我已经把眼睛蒙上了!'% name)
  16. cond.notify()
  17. cond.wait()
  18. for i in range(3):
  19. print('%s is finding!!!'% name)
  20. time.sleep(2)
  21. cond.notify()
  22. cond.release()
  23. print('%s :我赢了!'% name)
  24. def Hider(cond, name):
  25. cond.acquire()
  26. cond.wait()
  27. for i in range(2):
  28. print('%s is hiding!!!'% name)
  29. time.sleep(3)
  30. print('%s :我已经藏好了,你快来找我吧!'% name)
  31. cond.notify()
  32. cond.wait()
  33. cond.release()
  34. print('%s :被你找到了,唉~^~!'% name)
  35. if __name__ == '__main__':
  36. cond = threading.Condition()
  37. seeker = threading.Thread(target=Seeker, args=(cond, 'seeker'))
  38. hider = threading.Thread(target=Hider, args=(cond, 'hider'))
  39. seeker.start()
  40. hider.start()

线程事件

  • event = threading.Event()
  • event.set()
  • event.clear():将event.set()清除
  • event.wait():只有event.set()之后才执行
  1. import threading, time
  2. import random
  3. def light():
  4. if not event.isSet(): #初始化evet的flag为真
  5. event.set() #wait就不阻塞 #绿灯状态
  6. count = 0
  7. while True:
  8. if count < 10:
  9. print('\033[42;1m---green light on---\033[0m')
  10. elif count < 13:
  11. print('\033[43;1m---yellow light on---\033[0m')
  12. elif count < 20:
  13. if event.isSet():
  14. event.clear()
  15. print('\033[41;1m---red light on---\033[0m')
  16. else:
  17. count = 0
  18. event.set() #打开绿灯
  19. time.sleep(1)
  20. count += 1
  21. def car(n):
  22. while 1:
  23. time.sleep(random.randrange(3, 10))
  24. #print(event.isSet())
  25. if event.isSet():
  26. print("car [%s] is running..." % n)
  27. else:
  28. print('car [%s] is waiting for the red light...' % n)
  29. event.wait() #红灯状态下调用wait方法阻塞,汽车等待状态
  30. if __name__ == '__main__':
  31. car_list = ['BMW', 'AUDI', 'SANTANA']
  32. event = threading.Event()
  33. Light = threading.Thread(target=light)
  34. Light.start()
  35. for i in car_list:
  36. t = threading.Thread(target=car, args=(i,))
  37. t.start()

线程池:ThreadPoolExecutor

https://www.yuque.com/jiangwei-3zuwt/lyigmh/tf8ufs

介绍python的线程,需要介绍GIL锁的概念:

GIL不是Python特性
GIL是Python解释器(Cpython)时引入的概念,在JPython、PyPy中没有GIL。GIL并不是Python的语言缺陷。
GIL定义
GIL,the Global Interpreter Lock,直译为“全局解释锁”
GIL存在原因
CPython在执行多线程的时候并不是线程安全的,所以为了程序的稳定性,加一把全局解释锁,能够确保任何时候都只有一个Python线程执行。
GIL的弊端

  • GIL对计算密集型的程序会产生影响。因为计算密集型的程序,需要占用系统资源。GIL的存在,相当于始终在进行单线程运算,这样自然就慢了。
  • IO密集型影响不大的原因在于,IO,input/output,这两个词就表明程序的瓶颈在于输入所耗费的时间,线程大部分时间在等待,所以它们是多个一起等(多线程)还是单个等(单线程)无所谓的。

这就好比,你在公交站等公交时,你们排队等公交(单线程)还是沿着马路一字排开等(多线程)是无所谓的。公交车(即input,即输入的资源)没来,哪种方式都是瞎折腾。