知行编程网知行编程网  2022-11-15 16:30 知行编程网 隐藏边栏  4 
文章评分 0 次,平均分 0.0
导语: 本文主要介绍了关于详解Python中的Thread线程模块的相关知识,包括时间模块,以及Python中的线程这些编程知识,希望对大家有参考作用。

threading.Thread

Thread 是 threading 模块中最重要的类之一,可用于创建线程。创建线程有两种方式:一种是继承Thread类,重写其run方法;另一种是创建一个threading.Thread对象,并将可调用对象作为参数传递给它的初始化函数(__init__)。进入。下面给出例子。

详细讲解Python中的Thread线程模块

先来看看通过继承threading.Thread类来创建线程的例子:

#coding=gbk
import threading, time, random
count = 0
class Counter(threading.Thread):
  def __init__(self, lock, threadName):
'''@summary: 初始化对象。
@param lock: 琐对象。
@param threadName: 线程名称。
'''
    super(Counter, self).__init__(name = threadName) 
#注意:一定要显式的调用父类的初始化函数。
    self.lock = lock
  def run(self):
'''@summary: 重写父类run方法,在线程启动后执行该方法内的代码。
'''
    global count
    self.lock.acquire()
    for i in xrange(10000):
      count = count + 1
    self.lock.release()
lock = threading.Lock()
for i in range(5): 
  Counter(lock, "thread-" + str(i)).start()
time.sleep(2)  
#确保线程都执行完毕
print count

在代码中,我们创建了一个继承 threading.Thread 的 Counter 类。初始化函数接收两个参数,一个是普通对象,另一个是线程名。在 Counter 中,继承自父类的 run 方法被重写,run 方法将一个全局变量一一递增 10000。

在下面的代码中,创建了五个 Counter 对象,并分别调用了它们的 start 方法。最后打印结果。这里我们解释一下run方法和start方法:它们都是继承自Thread,线程启动后会执行run()方法,相关逻辑可以写到run方法中(通常是调用run方法一个活动[活动]。); start() 方法用于启动线程。

再看看另外一种创建线程的方法:

import threading, time, random
count = 0
lock = threading.Lock()
def doAdd():
'''@summary: 将全局变量count 逐一的增加10000。
'''
  global count, lock
  lock.acquire()
  for i in xrange(10000):
    count = count + 1
  lock.release()
for i in range(5):
  threading.Thread(target = doAdd, args = (), name = 'thread-' + str(i)).start()
time.sleep(2)  
#确保线程都执行完毕
print count

在这段代码中,我们定义了 doAdd 方法,它将全局变量 count 逐个递增 10000。然后,创建了五个Thread对象,将函数对象doAdd作为参数传递给它的初始化函数,然后调用Thread对象的start方法。线程启动后,会执行doAdd函数。有必要介绍一下threading.Thread类的初始化函数原型:

def __init__(self, group=None, target=None, name=None, args=(), kwargs={})

参数group是预留的,用于将来扩展;

参数target是一个可调用对象(也称为activity[activity]),在线程启动后执行;

参数name是线程的名字。默认值为“Thread-N“,N是一个数字。

参数args和kwargs分别代表调用target时的参数列表和关键字参数。

Thread类还定义了以下常用方法与属性:

Thread.getName()
Thread.setName()
Thread.name

用于获取和设置线程的名称。


Thread.ident

获取线程的标识符。线程标识符是一个非零整数,该属性只有在调用start()方法后才有效,否则只返回None。


Thread.is_alive()


Thread.isAlive()

确定线程是否处于活动状态(活着)。线程从调用 start() 方法启动线程开始一直处于活动状态,直到 run() 方法完成执行或遇到未处理的异常并被中断。


Thread.join([timeout])

调用 Thread.join 将阻塞调用线程,直到被调用线程完成运行或超时。参数 timeout 为数值类型,表示超时时间。如果不提供此参数,则调用线程将被阻塞,直到被调用线程结束。以下示例说明了 join() 的用法:

import threading, time
def doWaiting():
  print 'start waiting:', time.strftime('%H:%M:%S')
  time.sleep(3)
  print 'stop waiting', time.strftime('%H:%M:%S')
thread1 = threading.Thread(target = doWaiting)
thread1.start()
time.sleep(1) 
#确保线程thread1已经启动
print 'start join'
thread1.join() 
#将一直堵塞,直到thread1运行结束。
print 'end join'
threading.RLock和threading.Lock

在 threading 模块中,定义了两种类型的锁:threading.Lock 和 threading.RLock。它们之间存在细微差别,通过比较以下两段代码来说明:

import threading
lock = threading.Lock() 
#Lock对象
lock.acquire()
lock.acquire() 
#产生了死琐。
lock.release()
lock.release()
import threading
rLock = threading.RLock() 
#RLock对象
rLock.acquire()
rLock.acquire() 
#在同一线程内,程序不会堵塞。
rLock.release()
rLock.release()

两种锁的主要区别在于 RLock 允许在同一个线程中进行多次获取。锁不允许这样做。注意:如果使用RLock,acquire和release必须成对出现,即如果acquire被调用n次,release必须被调用n次才能真正释放被占用的琐事。


threading.Condition

条件可以理解为高级的琐碎,它提供了比Lock和RLock更高级的功能,可以让我们控制复杂的线程同步问题。 threadiong.Condition 内部维护了一个 trivial 对象(默认为 RLock),可以在创建 Condigtion 对象时作为参数传入。 Condition 还提供了acquire 和release 方法,与普通的acquire 和release 方法含义相同。其实就是简单的调用了内部平凡对象的对应方法。 Condition还提供了以下方法(请注意:这些方法只能在获取后调用,否则会报RuntimeError异常):

Condition.wait([timeout]):

wait 方法释放内部占用的杂务,线程被挂起,直到被通知唤醒或超时(如果提供了超时参数)。当线程被唤醒并重新占用时,程序将继续执行。

Condition.notify():

唤醒一个挂起的线程(如果有挂起的线程)。注意: notify() 方法不会释放占用的杂务。

Condition.notify_all()

Condition.notifyAll()

唤醒所有挂起的线程(如果有任何挂起的线程)。注意:这些方法不会释放占用的杂务。

现在写一个捉迷藏游戏,专门介绍threading.Condition的基本使用。假设这个游戏由两个人玩,一个隐藏(Hider),另一个寻找(Seeker)。游戏规则如下: 1、游戏开始后,Seeker先蒙上眼睛,蒙上眼睛后通知Hider; 2、Hider收到通知后,开始找地方躲起来。隐藏后,他通知 Seeker 可以 3. Seeker 收到通知后,开始寻找 Hider。 Hider 和 Seeker 都是独立的个体,在程序中由两个独立的线程表示。在游戏过程中,两者的行为具有一定的时间关系。我们通过Condition来控制这个时序关系。

#---- Condition
#---- 捉迷藏的游戏
import threading, time
class Hider(threading.Thread):
  def __init__(self, cond, name):
    super(Hider, self).__init__()
    self.cond = cond
    self.name = name
  def run(self):
    time.sleep(1) 
#确保先运行Seeker中的方法  
      
    self.cond.acquire() 
#b  
    print self.name + ': 我已经把眼睛蒙上了'
    self.cond.notify()
    self.cond.wait() 
#c  
              
#f 
    print self.name + ': 我找到你了 ~_~'
    self.cond.notify()
    self.cond.release()
               
#g
    print self.name + ': 我赢了' 
#h
      
class Seeker(threading.Thread):
  def __init__(self, cond, name):
    super(Seeker, self).__init__()
    self.cond = cond
    self.name = name
  def run(self):
    self.cond.acquire()
    self.cond.wait()  
#a  #释放对琐的占用,同时线程挂起在这里,直到被notify并重新占
有琐。
               
#d
    print self.name + ': 我已经藏好了,你快来找我吧'
    self.cond.notify()
    self.cond.wait()  
#e
               
#h
    self.cond.release() 
    print self.name + ': 被你找到了,哎~~~'
      
cond = threading.Condition()
seeker = Seeker(cond, 'seeker')
hider = Hider(cond, 'hider')
seeker.start()
hider.start()


threading.Event

Event 实现了与 Condition 类似的功能,但比 Condition 简单一些。它通过维护内部标识符来解决线程之间的同步问题。 (threading.Event 与 .NET 中的 System.Threading.ManualResetEvent 类做同样的事情。)

Event.wait([timeout])

阻塞线程,直到 Event 对象的内部标志设置为 True 或超时(如果提供了参数 timeout)。

Event.set()

将标识位设为Ture

Event.clear()

将标识伴设为False。

Event.isSet()

判断标识位是否为Ture。

下面使用Event来实现捉迷藏的游戏(用Event来实现可能不是很形象)

#---- Event
#---- 捉迷藏的游戏
import threading, time
class Hider(threading.Thread):
  def __init__(self, cond, name):
    super(Hider, self).__init__()
    self.cond = cond
    self.name = name
  def run(self):
    time.sleep(1) 
#确保先运行Seeker中的方法  
    print self.name + ': 我已经把眼睛蒙上了'
    self.cond.set()
    time.sleep(1)  
    self.cond.wait()
    print self.name + ': 我找到你了 ~_~'
    self.cond.set()     
    print self.name + ': 我赢了'
class Seeker(threading.Thread):
  def __init__(self, cond, name):
    super(Seeker, self).__init__()
    self.cond = cond
    self.name = name
  def run(self):
    self.cond.wait()
    print self.name + ': 我已经藏好了,你快来找我吧'
    self.cond.set()
    time.sleep(1)
    self.cond.wait()
    print self.name + ': 被你找到了,哎~~~'
cond = threading.Event()
seeker = Seeker(cond, 'seeker')
hider = Hider(cond, 'hider')
seeker.start()
hider.start()


threading.Timer

threading.Timer 是 threading.Thread 的子类,可以在指定的时间间隔后执行操作。这是 Python 手册中的一个示例:

def hello():
  print "hello, world"
t = Timer(3, hello)
t.start() 
# 3秒钟之后执行hello函数。

threading模块中还有一些常用的方法没有介绍:

threading.active_count()

threading.activeCount()

获取当前活动的(alive)线程的个数。

threading.current_thread()

threading.currentThread()

获取当前的线程对象(Thread object)。

threading.enumerate()

获取当前所有活动线程的列表。

threading.settrace(func)

设置一个跟踪函数,用于在run()执行之前被调用。

threading.setprofile(func)

设置一个跟踪函数,用于在run()执行完毕之后调用。

threading模块的内容很多。

本文为原创文章,版权归所有,欢迎分享本文,转载请保留出处!

知行编程网
知行编程网 关注:1    粉丝:1
这个人很懒,什么都没写
扫一扫二维码分享