首页 后端开发 Python教程 举例详解Python中threading模块的几个常用方法

举例详解Python中threading模块的几个常用方法

Jun 06, 2016 am 11:18 AM
python threading

threading.Thread

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

#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()方法用于启动线程。

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

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类的初始化函数原型:

1

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

登录后复制

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

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

1

2

3

Thread.getName()

Thread.setName()

Thread.name

登录后复制

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

1

Thread.ident

登录后复制

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

1

2

Thread.is_alive()

Thread.isAlive()

登录后复制

判断线程是否是激活的(alive)。从调用start()方法启动线程,到run()方法执行完毕或遇到未处理异常而中断 这段时间内,线程是激活的。

1

Thread.join([timeout])

登录后复制

调用Thread.join将会使主调线程堵塞,直到被调用线程运行结束或超时。参数timeout是一个数值类型,表示超时时间,如果未提供该参数,那么主调线程将一直堵塞到被调线程结束。下面举个例子说明join()的使用:
 

1

2

3

4

5

6

7

8

9

10

11

12

13

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。它们之间有一点细微的区别,通过比较下面两段代码来说明:
 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

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()方法不会释放所占用的琐。

1

2

Condition.notify_all()

Condition.notifyAll()

登录后复制

唤醒所有挂起的线程(如果存在挂起的线程)。注意:这些方法不会释放所占用的琐。

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

#---- 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来实现不是很形象)


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

#---- 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手册上提供的一个例子:

1

2

3

4

5

def hello():

  print "hello, world"

t = Timer(3, hello)

t.start()

# 3秒钟之后执行hello函数。

登录后复制

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

1

2

threading.active_count()

threading.activeCount()

登录后复制

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

1

2

threading.current_thread()

threading.currentThread()

登录后复制

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

1

threading.enumerate()

登录后复制

获取当前所有活动线程的列表。
threading.settrace(func)

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

1

threading.setprofile(func)

登录后复制

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

threading模块的内容很多,一篇文章很难写全,更多关于threading模块的信息,请查询Python手册 threading模块。

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
2 周前 By 尊渡假赌尊渡假赌尊渡假赌
仓库:如何复兴队友
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒险:如何获得巨型种子
4 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

Linux系统自带Python解释器能删除吗? Linux系统自带Python解释器能删除吗? Apr 02, 2025 am 07:00 AM

关于Linux系统自带Python解释器的删除问题许多Linux发行版在安装时会预装Python解释器,它并非通过软件包管理器�...

Python 3.6加载Pickle文件报错"__builtin__"模块未找到怎么办? Python 3.6加载Pickle文件报错"__builtin__"模块未找到怎么办? Apr 02, 2025 am 07:12 AM

Python3.6环境下加载Pickle文件报错:ModuleNotFoundError:Nomodulenamed...

Debian Strings能否兼容多种浏览器 Debian Strings能否兼容多种浏览器 Apr 02, 2025 am 08:30 AM

“DebianStrings”并非标准术语,其具体含义尚不明确。本文无法直接评论其浏览器兼容性。然而,如果“DebianStrings”指的是在Debian系统上运行的Web应用,则其浏览器兼容性取决于应用本身的技术架构。大多数现代Web应用都致力于跨浏览器兼容性。这依赖于遵循Web标准,并使用兼容性良好的前端技术(如HTML、CSS、JavaScript)以及后端技术(如PHP、Python、Node.js等)。为了确保应用与多种浏览器兼容,开发者通常需要进行跨浏览器测试,并使用响应式

XML修改内容需要编程吗 XML修改内容需要编程吗 Apr 02, 2025 pm 06:51 PM

修改XML内容需要编程,因为它需要精准找到目标节点才能增删改查。编程语言有相应库来处理XML,提供API像操作数据库一样进行安全、高效、可控的操作。

手机XML转PDF,转换速度快吗? 手机XML转PDF,转换速度快吗? Apr 02, 2025 pm 10:09 PM

手机XML转PDF的速度取决于以下因素:XML结构的复杂性手机硬件配置转换方法(库、算法)代码质量优化手段(选择高效库、优化算法、缓存数据、利用多线程)总体而言,没有绝对的答案,需要根据具体情况进行优化。

XML如何修改注释内容 XML如何修改注释内容 Apr 02, 2025 pm 06:15 PM

对于小型XML文件,可直接用文本编辑器替换注释内容;对于大型文件,建议借助XML解析器进行修改,确保效率和准确性。删除XML注释时需谨慎,保留注释通常有助于代码理解和维护。进阶技巧中提供了使用XML解析器修改注释的Python示例代码,但具体实现需根据使用的XML库进行调整。修改XML文件时注意编码问题,建议使用UTF-8编码并指定编码格式。

有什么手机APP可以将XML转换成PDF? 有什么手机APP可以将XML转换成PDF? Apr 02, 2025 pm 08:54 PM

无法找到一款将 XML 直接转换为 PDF 的应用程序,因为它们是两种根本不同的格式。XML 用于存储数据,而 PDF 用于显示文档。要完成转换,可以使用编程语言和库,例如 Python 和 ReportLab,来解析 XML 数据并生成 PDF 文档。

如何在protobuf中定义枚举类型并关联字符串常量? 如何在protobuf中定义枚举类型并关联字符串常量? Apr 02, 2025 pm 03:36 PM

在protobuf中定义字符串常量枚举的问题在使用protobuf时,常常会遇到需要将枚举类型与字符串常量进行关联的情�...

See all articles