Python中线程编程之threading模块的使用详解

发表于 5年以前  | 总阅读数:894 次

threading.Thread

Thread 是threading模块中最重要的类之一,可以使用它来创建线程。有两种方式来创建线程:一种是通过继承Thread类,重写它的run方法;另一种是创建一个threading.Thread对象,在它的初始化函数(init)中将可调用对象作为参数传入。下面分别举例说明。先来看看通过继承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

在代码中,我们创建了一个Counter类,它继承了threading.Thread。初始化函数接收两个参数,一个是琐对象,另一个是线程的名称。在Counter中,重写了从父类继承的run方法,run方法将一个全局变量逐一的增加10000。在接下来的代码中,创建了五个Counter对象,分别调用其start方法。最后打印结果。这里要说明一下run方法 和start方法: 它们都是从Thread继承而来的,run()方法将在线程开启后执行,可以把相关的逻辑写到run方法中(通常把run方法称为活动[Activity]。);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。然后创建了5个Thread对象,把函数对象doAdd 作为参数传给它的初始化函数,再调用Thread对象的start方法,线程启动后将执行doAdd函数。这里有必要介绍一下threading.Thread类的初始化函数原型:


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

  •   参数group是预留的,用于将来扩展;
  •   参数target是一个可调用对象(也称为活动[activity]),在线程启动后执行;
  •   参数name是线程的名字。默认值为"Thread-N",N是一个数字。
  •   参数args和kwargs分别表示调用target时的参数列表和关键字参数。

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

Thread.getName()

Thread.setName()

Thread.name

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

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

判断线程是否是激活的(alive)。从调用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允许在同一线程中被多次acquire。而Lock却不允许这种情况。注意:如果使用RLock,那么acquire和release必须成对出现,即调用了n次acquire,必须调用n次的release才能真正释放所占用的琐。
threading.Condition

可以把Condiftion理解为一把高级的琐,它提供了比Lock, RLock更高级的功能,允许我们能够控制复杂的线程同步问题。threadiong.Condition在内部维护一个琐对象(默认是RLock),可以在创建Condigtion对象的时候把琐对象作为参数传入。Condition也提供了acquire, release方法,其含义与琐的acquire, release方法一致,其实它只是简单的调用内部琐对象的对应的方法而已。Condition还提供了如下方法(特别要注意:这些方法只有在占用琐(acquire)之后才能调用,否则将会报RuntimeError异常。):
Condition.wait([timeout]):

wait方法释放内部所占用的琐,同时线程被挂起,直至接收到通知被唤醒或超时(如果提供了timeout参数的话)。当线程被唤醒并重新占有琐的时候,程序才会继续执行下去。
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模块的内容很多,一篇文章很难写全,更多关于threading模块的信息,请查询Python手册 threading模块。

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:1年以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:1年以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:1年以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:1年以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:1年以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:1年以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:1年以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:1年以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:1年以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:1年以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:1年以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:1年以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:1年以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:1年以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:1年以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:1年以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:1年以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:1年以前  |  398次阅读  |  详细内容 »
 相关文章
Android插件化方案 5年以前  |  237229次阅读
vscode超好用的代码书签插件Bookmarks 2年以前  |  8063次阅读
 目录