调用方式
python的线程调用有两种方式。一种是直接调用,一种是继承式调用
直接调用
import threading,time#方法一def run(n): print(n) time.sleep(2)t1 = threading.Thread(target=run,args=("t1",))t2 = threading.Thread(target=run,args=("t2",))t1.start()t2.start()使用类的方法调用
#方法二(使用类的方法)import threading,timeclass MyThread(threading.Thread): def __init__(self,n): super(MyThread,self).__init__() self.n = n def run(self): #函数名必须为run print(self.n) time.sleep(2)t1 = MyThread(1)t2 = MyThread(2)t1.start()t2.start()
join和Daemon
join()等待线程结束后再往后继续运行
Daemon()守护线程
使用setDaemon(True)那么主线程不会等待子线程结束才结束,主线程结束后子线程也会直接结束,必须要在start之前设置否则会报错
python中默认为setDaemon(False),主线程结束了子线程依然会执行直到完毕。
join例子:
import threading,timeclass MyThread(threading.Thread): def __init__(self,n): super(MyThread,self).__init__() self.n = n def run(self): #函数名必须为run print(self.n) time.sleep(2) print('end')t1 = MyThread('t1')t2 = MyThread('t2')t1.start()t1.join()t2.start()t2.join()结果
setDaemon()例子
import threading,timeclass MyThread(threading.Thread): def __init__(self,n): super(MyThread,self).__init__() self.n = n def run(self): #函数名必须为run print(self.n) time.sleep(2) print('end')t1 = MyThread('t1')t2 = MyThread('t2')t1.setDaemon(True)t2.setDaemon(True)t1.start()t2.start()
结果
线程锁
子线程可以共享父线程的内存空间,当存在多个子线程需要同时修改一个数据的时候就可能出现问题
假设两个子线程执行的操作都是num+1,由于线程是同时执行的,第一个子线程先取num = 1 ,第二个线程有取出num依然为1,线程一结束后num更改为2,随之线程二结束num依然被改为2,就与我们的目标出现冲突,这个时候就需要用到线程锁了,当线程一访问num的时候线程二是无法访问num的,线程一结束后释放num线程二才能访问num,这就使得num的结果不会产生冲突了。
#线程锁示例import threadingnum = 0t_objs = []lock = threading.Lock()def run(): lock.acquire() #加锁 global num #声明全局变量 num += 1 #执行加一操作 lock.release() #释放锁for i in range(500): t = threading.Thread(target=run) t.start() t_objs.append(t)for t in t_objs: #等待所有线程结束 t.join()print(num)递归锁则是在一个锁里面又嵌套另外一个线程锁
#递归锁import threadingdef run1(): lock.acquire() global num num += 1 lock.release() return numdef run2(): lock.acquire() global num2 num2 += 1 lock.release() return num2def run3(): lock.acquire() res = run1() 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()结果
信号量(Semaphore)
线程锁每次只允许一个线程操作数据,Semaphore则可同时允许多个线程操作,当达到允许的最大值的时候后面的则需要等待,前面的线程执行完毕后才可执行,因此操作同一个数据的时候依然有可能出错
#信号量import threading,timedef run(num): semaphore.acquire() time.sleep(1) print(num) semaphore.release()semaphore = threading.BoundedSemaphore(3) #最多运行三个线程for i in range(10): t = threading.Thread(target=run,args=(i,)) t.start()
事件(Event)
Event默认内置了一个标志,初始值为False
event总共就四中方法:set()、clear()、wait()、is_set()
set()设置标志位为True
clear()设置标志位为False
wait()等待标志位设为True
is_set()判断标志位是否被设为True
已红绿灯为例说明,首先写出交通灯,event.clear()相当于红灯,event.set()相当于绿灯,红灯为5秒绿灯也为5秒,用count来计数,当count超过10的时候重置count,这样红绿灯就能以5秒为间隔循环运行
import time,threadingevent = threading.Event()def light(): count = 0 while True: if count >= 5 and count < 10: event.clear() #相当于红灯了 print("red light please wait...") elif count > 10 : event.set() #相当于绿灯 count = 0 else: print("go go go ...") time.sleep(1) count += 1再来写car
def car(): while True: if event.is_set(): #判断event是否被set,相当于检测是否为绿灯 print('run...') time.sleep(1) else: print('waiting for green light..') event.wait() print('green light is on go...')运行
l = threading.Thread(target=light)c = threading.Thread(target=car)l.start()c.start()最终的结果