再看python多线程------threading模块

现在把关于多线程的能想到的需要注意的点记录一下:

关于threading模块:

1、关于 传参问题

  如果调用的子线程函数需要传参,要在参数后面加一个“,”否则会抛参数异常的错误。

  如下:

1     for i in xrange(5):
2         threads.append(threading.Thread(target=worker,args=(i,)))

2、关于join()阻塞

  join()方法一旦被调用,这个线程就会被阻塞住,等其他线程执行完才执行自身。当我们在主线程A中,创建了n个子线程,这里需要注意,根据需求是应该去阻塞父线程还是子线程,比较下面例子:

  ---->子线程和父线程都不阻塞

 1 # -*- coding:utf-8 -*-
 2 import Queue,time,threading
 3 start = time.clock()
 4
 5 def worker(m):
 6     print ‘worker‘,m
 7     time.sleep(1)
 8     return
 9
10 if __name__ == "__main__":
11     threads = []
12     for i in xrange(5):
13         threads.append(threading.Thread(target=worker,args=(i,)))
14     for t in threads:
15         t.start()
16         #t.join()  #阻塞子线程
17
18     #t.join()   #阻塞父线程
19
20     end = time.clock()
21     print "finished: %.3fs" %(end-start)

得到输入:

worker 0
worker 1
worker 2
worker 3
worker 4
finished: 0.001s

这里,其实父线程已经结束,因为已经打印出了finished:0.001s,但是子线程并没有执行完,sleep 1秒之后,才出现“Process finished with exit code 0”的程序结束标志。

  

  ----->同样代码,当阻塞子线程时,输出如下:

worker 0
worker 1
worker 2
worker 3
worker 4
finished: 5.004s

这里,由于5个子线程都被阻塞了,所以它们会按序执行,同样,程序sleep了5秒,一定要注意,你这样做,程序的效率并没有提升,仍然需要5秒的时间。

  -------> 同样代码,当阻塞父线程时,输出如下:

worker 0
worker 1
worker 2
worker 3
worker 4
finished: 1.003s

这里,阻塞父线程,父线程会等待子线程结束,才会继续运行打印finished,程序的效率也得到了提升。

3、关于setDaemon()方法

  setDaemon()方法是设置在子线程中的,当我们在父线程A中创建了n个子线程之后,给我们喜欢的子线程设置setDaemon(True)后,当它们的父线程运行结束之后,不管这些子线程运行结束还是没结束,它会直接结束程序。这里,还有一个需要注意的,setDaemon()方法必须设置在start()方法之前,否则会抛RuntimeError异常。

  还用上面的例子:

 1 # -*- coding:utf-8 -*-
 2 import Queue,time,threading
 3 start = time.clock()
 4
 5 def worker(m):
 6     print ‘worker‘,m
 7     time.sleep(1)
 8     return
 9
10 if __name__ == "__main__":
11     threads = []
12     for i in xrange(5):
13         threads.append(threading.Thread(target=worker,args=(i,)))
14     for t in threads:
15         t.setDaemon(True)
16         t.start()
17         #t.join()  #阻塞子线程
18
19     #t.join()   #阻塞父线程
20
21     end = time.clock()
22     print "finished: %.3fs" %(end-start)

 这里,没有阻塞父线程,得到的输出如下:

worker 0
worker 1
worker 2
worker 3
worker 4
finished: 0.001s

说明,主线程一旦结束,会直接把子线程的内存回收,结束整个进程的运行。子进程的sleep 1没有执行就退出了。对于某些辅助子线程的应用场景,这个应该会有用。

4、创建子线程的两种方式

  第一种是上面提到的,创建子线程要执行的函数(worker),然后把这个函数传递进threading.Thread的对象中,让它来执行;

  第二种是直接从threading.Thread类继承,创建一个新的类,通过重写这个新的类里面的run()方法,实现子线程要执行的内容,例如:

 1 # -*- coding:utf-8 -*-
 2 __author__ = ‘webber‘
 3 import threading,time
 4
 5 class Mythread(threading.Thread):
 6
 7     def __init__(self,m):
 8         threading.Thread.__init__(self)
 9         self.m = m
10
11     def run(self):
12         print ‘worker‘, self.m
13         time.sleep(1)
14         return
15
16 if __name__ == "__main__":
17     start = time.clock()
18
19     threads = []
20     for i in xrange(5):
21         threads.append(Mythread(i))
22     for t in threads:
23         t.start()
24
25     t.join()
26     end = time.clock()
27     print "finished: %.3fs" % (end - start)

输出和上面的主线程阻塞的结果一样

这里要注意一下黄色部分,调用的时候的传参方式。

5、关于锁----> Lock、RLock、Condition方法

  之前有提到,由于python理论上是无法实现真正意义上的多线程的,即使你有多个CPU,python的多线程也只能利用一个,那么为了防止在多线程中对共享数据空间的数据修改时发生的尴尬,threading模块继承了thread模块的Lock方法,这是最简单的锁,实现也比较简单,只需要在子线程中修改数据前后分别加上锁和释放锁即可。

就是以下三句话:

  a、主函数中创建一个锁的对象: 例如: lock = threading.Lock()    #返回一个新的Lock对象,创建一把锁。

  b、在子线程需要对数据进行修改之前,lock.acquire()       #获取这把锁

  c、在子线程对数据进行修改之后,  lock.acquire()    #释放这把锁

下面有个代码应用小例子:

 1 # -*- coding:utf-8 -*-
 2 __author__ = ‘webber‘
 3 import threading, time, random
 4
 5 dish = 0
 6 lock = threading.Lock()
 7
 8
 9 def producerFunction():
10     ‘‘‘如果投的筛子比0.5大,则向盘子中增加一个苹果‘‘‘
11     global lock, dish
12     while dish < 10:
13         if (random.random() > 0.5):
14             lock.acquire()
15             dish += 1
16             print(‘生产者增加了一个苹果,现在有%d个苹果‘ % (dish,))
17             lock.release()
18             time.sleep(random.random() * 3)
19
20
21 def consumerFunction():
22     ‘‘‘如果投的筛子比0.5小,则从盘子中取一个苹果‘‘‘
23     global lock, dish
24     while dish > 0:
25         if (random.random() < 0.5):
26             lock.acquire()
27             dish -= 1
28             print(‘消费者拿走一个苹果现,现在有%d个苹果‘ % (dish,))
29             lock.release()
30             time.sleep(random.random() * 3)
31
32
33 def begin():
34     ident1 = threading.Thread(target=producerFunction())
35     ident2 = threading.Thread(target=consumerFunction())
36     ident1.start()
37     ident2.start()
38
39
40 if __name__ == ‘__main__‘:
41     begin()

  其次,threading模块提出了一个更高级的锁RLock,它的出现是为了解决Lock可能会出现的死锁问题,即:当由于疏忽时,可能会出现一个子线程内同一把锁对象连续acquire()两次,那么由于第一次的acquire没有release,那么第二次的acquire请求会把该子线程挂起,导致lock对象永远不会release,造成死锁。而RLock对象允许一个线程多次对其进行acquire操作,在其内部通过counter变量维护着线程acquire的次数,而每一次的acquire操作必须有一个release操作与之对应,在所有的release操作完成之后,别的线程才能申请该RLock对象。使用上暂时我就把它当成Lock方法试了试,通过。~~~

  最后,threading模块提供了更高级的封装,算是一种高级的多线程间同步方式,包括threading.Event和threading.Condition,其中,threading.Event为简单的同步方式,一个进程标记为event,其他的进程就需要等待,用到下面几种方法:

Event.wait([timeout]) 阻塞线程,直到Event对象内部标识位被设置为True或超时(如果提供了参数timeout)
Event.set() 将标识号设为True
Event.clear() 设为标识符False

 

  threading.Condition 可以把Condition理解为更高级的锁,它提供了比RLock更高级的功能,允许我们能够控制复杂的线程同步问题,它在内部维护了一个锁对象(默认为RLock),可以在创建Condition对象的时候把锁对象作为参数传入。Condition也提供了acquire和release方法,它的特色在于内部的wait和notify机制,具体可看threading模块,下面的方法只有在对象获取到锁之后才能调用,否则,将会抛RuntimeError异常。

Condition.wait([timeout]):  wait方法释放内部所占用的琐,同时线程被挂起,直至接收到通知被唤醒或超时(如果提供了timeout参数的话)。当线程被唤醒并重新占有琐的时候,程序才会继续执行下去。 
Condition.notify() 唤醒一个挂起的线程(如果存在挂起的线程)。注意:notify()方法不会释放所占用的琐。
Condition.notify_all() 唤醒所有挂起的线程(如果存在挂起的线程)。注意:这些方法不会释放所占用的琐。

参考:http://orangeholic.iteye.com/blog/1720421

6、其他方法

  由于threading是继承的thread模块的,所以还有些公共属性方法,比如:

t.getName():获取子线程的名称,默认为:Tread-n (n为线程序列号)

t.setName():设置子线程的名称

t.ident:获取线程标识符,要在t.start()之后调用才有效,否则返回None

t.is_alive():判断子线程是否激活,返回True或False

关于Semaphore、event、Condition的具体实例,没再去尝试,以后遇到再试,可参考这篇博客:

    http://www.jb51.net/article/57672.htm

时间: 2024-10-20 15:11:53

再看python多线程------threading模块的相关文章

Python 多线程threading模块

首先,我们在了解多线程时需要理解的就是什么是多线程,按照官方的解释就是:多线程(英语:multithreading),是指从软件或者硬件上实现多个线程并发执行的技术. 在我自学到这里的时候,通过会在想进程和线程到底是有什么区别,我的理解就是: 进程就是一个应用程序在处理机上的一次执行过程,它是一个动态的概念,而线程是进程中的一部分,一个进程可以包含多个线程. 下面就以简单的例子来加强我们对python 线程的理解. 默认情况下,我们在没有启动线程的时候,可以看一下程序总的运行时间,应该是每个函数

python多线程-threading模块

threading 是我们常用的用于 python 多线程的模块,其功能更加丰富.下面我们就来开始学习这个模块. 同样的,我这里声明一样我使用的版本是 python2.7,不同版本直接可能存在差异. 老规矩,使用 help() 函数获取帮助文档,看看里面有什么内容. threading 模块中提供了一个 thread 的类,注意不要和 thread 模块搞混了,两者差别还是很大的.thread 这个类可以实例化一个对象,每个对象代表一个线程,可以调用其中的 run() 方法来开启一个线程的运行.

python 的threading模块

其中Thread类 是你主要的线程类,可以创建进程实例.该类提供的函数包括: getName(self) 返回线程的名字 isAlive(self) 布尔标志,表示这个线程是否还在运行中 isDaemon(self) 返回线程的daemon标志,将线程放入后台执行 join(self, timeout=None) 程序挂起,直到线程结束,如果给出timeout,则最多阻塞timeout秒,主线程需等待子线程完成 run(self) 定义线程的功能函数 setDaemon(self, daemon

python中threading模块详解(一)

python中threading模块详解(一) 来源 http://blog.chinaunix.net/uid-27571599-id-3484048.html threading提供了一个比thread模块更高层的API来提供线程的并发性.这些线程并发运行并共享内存. 下面来看threading模块的具体用法: 一.Thread的使用 目标函数可以实例化一个Thread对象,每个Thread对象代表着一个线程,可以通过start()方法,开始运行. 这里对使用多线程并发,和不适用多线程并发做

python多线程-thread模块

thread 和 threading 模块都能够实现 python 中的多线程,一般而言使用 threading 更加方便,因为 thread 有很多的缺点,例如当主线程结束后,所以子线程都会强制终止掉,没有警告也没有正常的清理工作.所以一般情况下更推荐使用 threading 模块.不过出于学习的目的,我们两个模块都来看一下. 在进行代码学习之前,我们要先来了解 python 的 GIL,也就是全局解释器锁.这个锁保证了同一时刻只能有一个线程运行. 等等……我明明要使用多线程,为什么这个锁却保

python之threading模块简单讲解和实例演示

import threading 在处理一些程序时为了节约时间,可以使用多线程的方式, 让其并发去执行,从而节约时间, (注意python其实是伪多线程,其实是以我们感觉不到的速度每行代码都按照相同时间执行) Lock 当多线程同时对一个变量进行修改操作的时候,那么可能会出现混乱, 因为其是并发(算是吧)而行, (所以当两个赋值时间相对接近时那么其容易出现混乱) 所以我们得创建锁, 让其上一个线程赋值结束, 下一个赋值再继续 threading.Lock() 创建锁 是可用的最低级的同步指令.

【Python之旅】第七篇(一):再谈Python多线程

主要是再进一步加深Python中关于多线程相关函数join()的理解以解多线程的执行过程.这里通过下面的例子来作进一步的说明. 1.多线程与主程序代码的执行顺序关系 给出下面程序代码: #!/usr/bin/env python import threading import time def sayHi(n): time.sleep(1) print 'Hi this is thread %s' %n thread_list = []    #用来存放多线程执行返回的函数入口,因此这里存放的是

Py西游攻关之多线程(threading模块)

线程与进程 什么是线程(thread)? 线程是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务 A thread is an execution context, which is all the information a CPU needs to execute a stream of instructions. Suppose you're reading a

多线程threading模块

threading模块是python中专门提供用来做多线程的模块.threading中最常用的类是thread. 查看线程数量函数:threading.enumerate() 查看线程当前名字函数:threading.current_thread() 以下看一个简单的多线程程序: #encoding: utf-8#采用多线程的方式import threadingimport time def coding(): for x in range(3): print('正在写代码%s'%threadi