多线程模块 threading
-
创建多线程的两种方式:
import threading import time
-
创建线程的第一种方式
def foo(n): pass print('hello world') t1 = threading.Thread(target=foo, args=(1,)) t1.start()
-
创建线程的第二种方式
```
class MyThread(threading.Thread):
def __init__(self, num):
threading.Thread.__init__(self)
self.num = num # 对象里的字段 # self 是 t1或t2
def run(self):
print("running on number: %s" % self.num)
time.sleep(3)
if __name__ == '__main__':
t1 = MyThread(1) # 实例化一个类的对象,执行构造方法
t2 = MyThread(2)
t1.start()
t2.start()
```
- 创建线程:
import threading
t1 = threading.Thread(target=music, args=('七里香',))
target指向函数,args指向函数的参数
-
启动线程:
t.start()
-
阻塞线程:
t.join() 阻塞直到线程t结束
-
多线程实例1
import threading from time import ctime, sleep import time # 预计耗时4秒 def music(func): for i in range(2): print("I was listening to %s. %s" % (func, ctime())) sleep(2) print("end listening %s" %ctime()) # 预计耗时6秒 def movie(func): for i in range(2): print("Begin watching at the %s! %s" % (func,ctime())) sleep(3) print("end watching %s" % ctime()) # 创建线程1,2 threads = [] t1 = threading.Thread(target=music, args=('七里香',)) threads.append(t1) t2 = threading.Thread(target=movie, args=('十三区',)) threads.append(t2) if __name__ == '__main__': for t in threads: t.start() start = time.time() t2.join() end = time.time() # t2.join() # join阻塞 print("总共耗时 %s" % (end-start)) # 结果:总共耗时 6.004828929901123
-
多线程 -- 计算密集型
import threading import time begin = time.time() def add(n): sum = 0 for i in range(n): sum += i print(sum) # 单线程串行计算 # add(10000000) # add(10000000) # 多线程并行计算 t1 = threading.Thread(target=add, args=(10000000,)) t1.start() # print('1开始了') t2 = threading.Thread(target=add, args=(10000000,)) t2.start() # print('2也开始了') t1.join() t2.join() # end = time.time() print(end-begin) # 串行花费 14.73 秒 两者都是计算密集型,都在抢CPU # 并行花费 15.71 秒 并行反而更多,因为切换还需要时间 # IO密集型任务或函数 # 计算密集型任务 # GIL全局解释锁 如果只有一颗CPU,无法解决计算密集型的任务 只有Cpython有这个bug
-
多线程 -- IO密集型
import time import threading def foo(n): # 设定3秒 print('线程1开始') print('foo %s' % n) # print('foo') time.sleep(3) print('线程1结束\n') def bar(n): # 设定1秒 print('线程2开始') print('bar %s' % n) time.sleep(1) # print('ok') print('线程2结束') # t1 t2 即为线程 # target = 要执行的函数 args = 参数 t1 = threading.Thread(target=foo, args=(1,)) t2 = threading.Thread(target=bar, args=(2,)) print('...... in the main ........') # 线程执行 start() begin = time.time() t1.start() # 线程开始 t2.start() # 线程开始 t1.join() # 子线程不结束不往下走 t2.join() # 子线程不结束不往下走 end = time.time() print('整个程序一共花了', end - begin, '秒,asshole') # # 运行结果: 整个程序一共花了 3.003476858139038 秒,asshole
-
死锁
# 死锁怎么办? # 用递归锁解决死锁问题,递归锁可重用 import threading, time class myThread(threading.Thread): def doA(self): # lockA.acquire() lock.acquire() # 加锁 # 为什么在外面加了一把锁后还要在里面再加一把锁 print(self.name, "gotlockA", time.ctime()) time.sleep(1) # lockB.acquire() lock.acquire() # 加第二把锁 print(self.name, "gotlockB", time.ctime()) # lockB.release() lock.release() # 释放第一把锁 # lockA.release() lock.release() # 释放第二把锁 def doB(self): lock.acquire() print(self.name, "gotlockB", time.ctime()) time.sleep(1) lock.acquire() print(self.name, "gotlockA", time.ctime()) lock.release() lock.release() def run(self): # 类似于构造方法 self.doA() self.doB() if __name__ == "__main__": # lockA = threading.Lock() # 普通锁 # lockB = threading.Lock() lock = threading.RLock() # Rlock 叫递归锁,可重用 threads = [] for i in range(5): threads.append(myThread()) for t in threads: t.start() for t in threads: t.join() # 等待线程结束,后面再讲。
-
同步锁
# 加锁后会加锁的部分变成串行 import time import threading def addNum(): global num # 在每个线程中都获取这个变量 print('fuck off') # num -= 1 # 此操作的时间远小于CPU切换的时间 # 加锁,被加锁的部分是串行 r.acquire() ####### 加锁 temp = num # 1 # time.sleep(0.001) # 2 有可能取了数99后,执行完这两步后CPU转到另外的线程上去了, print('ok') # 另外的线程取到99,执行减1,CPU再转回当前线程,又执行99-1,重复了 time.sleep(0.0002) num = temp - 1 r.release() ######## 释放锁 num = 100 thread_list = [] r = threading.Lock() # python的GIL锁 # 用for循环创建100个线程 for i in range(100): t = threading.Thread(target=addNum) t.start() # t.join() # join阻塞,可以得到正确的结果,从但是变成了串行,失去了多线程的意义 # join虽然可以得到正确结果,但是除了计算的其他部分也会变成并行 thread_list.append(t) for t in thread_list: t.join() print("\nfinal num:", num) # num减1的速度如果 # GIL保证只有一个线程进入解释器 # 自己加的锁是锁CPU,在我释放锁之前你不要切换了
-
event
# event 类似condition # event.isSet():返回event的状态值; # # event.wait():如果 event.isSet()==False将阻塞线程; # # event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度; # # event.clear():恢复event的状态值为False。 import threading, time class Boss(threading.Thread): def run(self): print("BOSS: 今晚大家都要加班到22:00") event.is_set() or event.set() time.sleep(2) print("BOSS:<22:00>可以下班了。 ") event.is_set() or event.set() class Worker(threading.Thread): def run(self): event.wait() print("Worker:哎,命苦啊") time.sleep(0.25) event.clear() event.wait() print("Worker: OhYear!") if __name__ == "__main__": event = threading.Event() threads = [] for i in range(5): threads.append(Worker()) threads.append(Boss()) for t in threads: t.start() for t in threads: t.join()
-
多线程利器 QUEUE队列
# 队列里本身就有一把锁 # # import queue, time, threading # # d = queue.Queue(3) # # d.put('jinxing',0) #插入数据 # d.put('xiaohu') # d.put('haoran') # # print(d.get()) # print(d.get()) # print(d.get()) # # # print(d.qsize()) # li = [1,2,3,4,5] # # def pri(): # while li: # a = li[-1] # print(a) # time.sleep(1) # try: # li.remove(a) # except: # print('----',a) # # t1 = threading.Thread(target=pri, args=()) # t1.start() # t2 = threading.Thread(target=pri, args=()) # t2.start() import threading, queue from time import sleep from random import randint class Production(threading.Thread): # 生产者 def run(self): while True: r = randint(0, 100) q.put(r) print("生产出来%s号包子" % r) sleep(1) class Proces(threading.Thread): # 消费者 def run(self): while True: re = q.get() print("吃掉%s号包子" % re) sleep(1) if __name__ == "__main__": q = queue.Queue(10) threads = [Production(), Production(), Production(), Proces()] for t in threads: t.start()