线程
线程是进程独立的一条运行线路,是处理器调度的最小单位。
threading模块
直接调用
import threading import time def sayhi(num): #定义每个线程要运行的函数 print("running on number:%s" %num) time.sleep(3) if __name__ == '__main__': t1 = threading.Thread(target=sayhi,args=(1,)) #生成一个线程实例 t2 = threading.Thread(target=sayhi,args=(2,)) #生成另一个线程实例 t1.start() #启动线程 t2.start() #启动另一个线程 print(t1.getName()) #获取线程名 print(t2.getName())
继承式调用
import threading import time class MyThread(threading.Thread): def __init__(self,num): threading.Thread.__init__(self) self.num = num 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()
注意:继承式调用中运行的函数名必须是run,因为它只是重写父类中的run方法,并且由start调用run
join与daemon
join:让主线程等待子线程结束。
daemon:守护线程不管自己的工作是否完成,都会跟着主线程的结束而结束。
import time import threading def run(n): print('[%s]------running---- ' % n) time.sleep(2) print('--done--') def main(): for i in range(5): t = threading.Thread(target=run,args=[i,]) t.start() t.join(1) print('starting thread', t.getName()) m = threading.Thread(target=main,args=[]) m.setDaemon(True) #将main线程设置为Daemon线程,它做为程序主线程的守护线程,当主线程退出时,m线程也会退出,由m启动的其它子线程会同时退出,不管是否执行完任务 m.start() m.join(timeout=2) print("---main thread done----")
线程锁(进程锁)
线程锁的作用是为了保护临界资源,在一个线程没有完成对某个资源的修改,其他线程是不被运行修改该资源(说白了就是被一个上锁的线程访问的资源,不能被另一个线程访问)。
GIL:是cpython编译器独有的特性,同一时间只允许一个线程使用cpu,但这并不意味着该线程对cpu的占用会持续到该线程的结束,这就违背了多线程的含义,而是cpu快速的做着上下文切换,这种速度是肉眼观察不到的,使我们认为这些线程是并行处理的,但是当两个线程同时需要修改某份数据时,例如有一个变量n=1,现在a线程与b线程的任务都是对n进行+1操作,当a线程执行到一半时(已读到n=1),cpu进行上下切换,b线程占用cpu完成了对n的+1操作,并行写入内存,这时cpu在切回a线程完成未完成的工作,这时a线程的n的数值为2并且写入内存,但事实上我们的需求时要求n=3,这时线程锁的作用就提现了。
import time import threading def addNum(): global num #在每个线程中都获取这个全局变量 print('--get num:',num ) time.sleep(1) num -=1 #对此公共变量进行-1操作 num = 100 #设定一个共享变量 thread_list = [] for i in range(100): t = threading.Thread(target=addNum) t.start() thread_list.append(t) for t in thread_list: #等待所有线程执行完毕 t.join() print('final num:', num )
import time import threading def addNum(): global num #在每个线程中都获取这个全局变量 print('--get num:',num ) time.sleep(1) lock.acquire() #修改数据前加锁 num -=1 #对此公共变量进行-1操作 lock.release() #修改后释放 num = 100 #设定一个共享变量 thread_list = [] lock = threading.Lock() #生成全局锁 for i in range(100): t = threading.Thread(target=addNum) t.start() thread_list.append(t) for t in thread_list: #等待所有线程执行完毕 t.join() print('final num:', num )
递归锁
递归锁顾名思义就是大锁里面加小锁
import threading,time def run1(): print("grab the first part data") lock.acquire() global num num +=1 lock.release() return num def run2(): print("grab the second part data") lock.acquire() global num2 num2+=1 lock.release() return num2 def run3(): lock.acquire() res = run1() print('--------between run1 and run2-----') res2 = run2() lock.release() print(res,res2) if __name__ == '__main__': num,num2 = 0,0 lock = threading.RLock() for i in range(10): t = threading.Thread(target=run3) t.start() while threading.active_count() != 1: print(threading.active_count()) else: print('----all threads done---') print(num,num2)
信号量
同时允许多个线程处理数据
import threading,time def run(n): semaphore.acquire() time.sleep(1) print("run the thread: %s " %n) semaphore.release() if __name__ == '__main__': num= 0 semaphore = threading.BoundedSemaphore(5) #最多允许5个线程同时运行 for i in range(20): t = threading.Thread(target=run,args=(i,)) t.start() while threading.active_count() != 1: pass #print threading.active_count() else: print('----all threads done---') print(num)
Timer
创建一个有延迟的线程
def hello(): print("hello, world") t = Timer(30.0, hello) t.start() # 在30s后,再打印hello world!
events
具有亲缘关系的线程间状态通信
import time import threading event = threading.Event() def lighter(): count = 0 event.set() #先设置绿灯 while True: if count >5 and count < 10: #改成红灯 event.clear() #把标志位清了 print("