当前位置: 移动技术网 > IT编程>脚本编程>Python > Python线程同步的实现代码

Python线程同步的实现代码

2018年11月03日  | 移动技术网IT编程  | 我要评论

网贷资讯聚集地,无尽的休止符,126卡盟

本文介绍python中的线程同步对象,主要涉及 thread 和 threading 模块。

threading 模块提供的线程同步原语包括:lock、rlock、condition、event、semaphore等对象。

线程执行

join与setdaemon

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

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

import threading
import time


def get_thread_a():
 print("get thread a started")
 time.sleep(3)
 print("get thread a end")


def get_thread_b():
 print("get thread b started")
 time.sleep(5)
 print("get thread b end")


if __name__ == "__main__":
 thread_a = threading.thread(target=get_thread_a)
 thread_b = threading.thread(target=get_thread_b)
 start_time = time.time()
 thread_b.setdaemon(true)
 thread_a.start()
 thread_b.start()
 thread_a.join()
 
 end_time = time.time()
 print("execution time: {}".format(end_time - start_time))

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

get thread a started
get thread b started
get thread a end
execution time: 3.003199815750122

线程同步

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

python对线程加锁主要有lock和rlock模块

lock: 

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

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

rlock:

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

from threading import rlock
lock = rlock()
lock.acquire()
lock.acquire()
lock.release()
lock.release() 

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

import threading

def 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 conversation
a : hello b,that's ok
b : how are you
a : i'm fine,and you?
b : i'm fine too
a : nice to meet you
b : nice to meet you,too
a : that's all for today
b : oh,goodbye

semaphore(信号量)

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

import time
import threading


def 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 rc

def release(self):
  with self._cond:
   self._value += 1
   self._cond.notify()

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对移动技术网的支持。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网