盈佳国际W11唯一指定平台
  咨询电话:15564458115

盈佳国际官方备用首页

Python线程同步

线程执行

join与setDaemon

子线程在主线程运行结束后,会继续执行完,如果给子线程设置为守护线程(setDaemon=True),主线程运行结束子线程即结束;

如果join()线程,那么主线程会等待子线程执行完再执行。

 

1 import threading 2 import time 3 4 5 def get_thread_a(): 6 print("get thread A started") 7 time.sleep(3) 8 print("get thread A end") 9 10 11 def get_thread_b():12 print("get thread B started")13 time.sleep(5)14 print("get thread B end")15 16 17 if __name__ == "__main__":18 thread_a = threading.Thread(target=get_thread_a)19 thread_b = threading.Thread(target=get_thread_b)20 start_time = time.time()21 thread_b.setDaemon(True)22 thread_a.start()23 thread_b.start()24 thread_a.join()25 26 end_time = time.time()27 print("execution time: {}".format(end_time - start_time))

 

thread_a是join,首先子线程thread_a执行,thread_b是守护线程,当主线程执行完后,thread_b不会再执行执行结果如下:

get thread A startedget thread B startedget thread A endexecution time: 3.003199815750122

线程同步

当线程间共享全局变量,多个线程对该变量执行不同的操作时,该变量最终的结果可能是不确定的(每次线程执行后的结果不同),如:对count变量执行加减操作 ,count的值是不确定的,要想count的值是一个确定的需对线程执行的代码段加锁。

python对线程加锁主要有Lock和Rlock模块

Lock:

from threading import Locklock = Lock()lock.acquire()lock.release()

Lock有acquire()和release()方法,这两个方法必须是成对出现的,acquire()后面必须release()后才能再acquire(),否则会造成死锁

Rlock:

鉴于Lock可能会造成死锁的情况,RLock(可重入锁)对Lock进行了改进,RLock可以在同一个线程里面连续调用多次acquire(),但必须再执行相同次数的release()

from threading import RLocklock = RLock()lock.acquire()lock.acquire()lock.release()lock.release()

condition(条件变量),线程在执行时,当满足了特定的条件后,才可以访问相关的数据

import threadingdef get_thread_a(condition): with condition: condition.wait() print("A : Hello B,that"s ok") condition.notify() condition.wait() print("A : I"m fine,and you?") condition.notify() condition.wait() print("A : Nice to meet you") condition.notify() condition.wait() print("A : That"s all for today") condition.notify()def get_thread_b(condition): with condition: print("B : Hi A, Let"s start the conversation") condition.notify() condition.wait() print("B : How are you") condition.notify() condition.wait() print("B : I"m fine too") condition.notify() condition.wait() print("B : Nice to meet you,too") condition.notify() condition.wait() print("B : Oh,goodbye")if __name__ == "__main__": condition = threading.Condition() thread_a = threading.Thread(target=get_thread_a, args=(condition,)) thread_b = threading.Thread(target=get_thread_b, args=(condition,)) thread_a.start() thread_b.start()

Condition内部有一把锁,默认是RLock,在调用wait()和notify()之前必须先调用acquire()获取这个锁,才能继续执行;当wait()和notify()执行完后,需调用release()释放这个锁,在执行with condition时,会先执行acquire(),with结束时,执行了release();所以condition有两层锁,最底层锁在调用wait()时会释放,同时会加一把锁到等待队列,等待notify()唤醒释放锁

wait() :允许等待某个条件变量的通知,notify()可唤醒

notify(): 唤醒等待队列wait()

执行结果:

B : Hi A, Let"s start the conversationA : Hello B,that"s okB : How are youA : I"m fine,and you?B : I"m fine tooA : Nice to meet youB : Nice to meet you,tooA : That"s all for todayB : Oh,goodbye

 

 

Semaphore(信号量)

 用于控制线程的并发数,如爬虫中请求次数过于频繁会被禁止ip,每次控制爬取网页的线程数量可在一定程度上防止ip被禁;文件读写中,控制写线程每次只有一个,读线程可多个。

import timeimport threadingdef get_thread_a(semaphore,i): time.sleep(1) print("get thread : {}".format(i)) semaphore.release()def get_thread_b(semaphore): for i in range(10): semaphore.acquire() thread_a = threading.Thread(target=get_thread_a, args=(semaphore,i)) thread_a.start()if __name__ == "__main__": semaphore = threading.Semaphore(2) thread_b = threading.Thread(target=get_thread_b, args=(semaphore,)) thread_b.start()

上述示例了每隔1秒并发两个线程执行的情况,当调用一次semaphore.acquire()时,Semaphore的数量就减1,直至Semaphore数量为0时被锁上,当release()后Semaphore数量加1。Semaphore在本质上是调用的Condition,semaphore.acquire()在Semaphore的值为0的条件下会调用Condition.wait(), 否则将值减1,semaphore.release()会将Semaphore的值加1,并调用Condition.notify()

Semaphore源码

def acquire(self, blocking=True, timeout=None): if not blocking and timeout is not None: raise ValueError("can"t specify timeout for non-blocking acquire") rc = False endtime = None with self._cond: while self._value == 0: if not blocking: break if timeout is not None: if endtime is None: endtime = _time() + timeout else: timeout = endtime - _time() if timeout <= 0: break self._cond.wait(timeout) else: self._value -= 1 rc = True return rcdef release(self): with self._cond: self._value += 1 self._cond.notify()