再看python多线程------threading模块
现在把关于多线程的能想到的需要注意的点记录一下:
关于threading模块:
1、关于 传参问题
如果调用的子线程函数需要传参,要在参数后面加一个“,”否则会抛参数异常的错误。
如下:
for i in xrange(5):
threads.append(threading.Thread(target=worker,args=(i,)))
2、关于join()阻塞
join()方法一旦被调用,这个线程就会被阻塞住,等其他线程执行完才执行自身。当我们在主线程A中,创建了n个子线程,这里需要注意,根据需求是应该去阻塞父线程还是子线程,还有就是t.join()放的位置,比较下面例子:
---->子线程和父线程都不阻塞
# -*- coding:utf-8 -*-
import Queue,time,threading
start = time.clock() def worker(m):
print 'worker',m
time.sleep(1)
return if __name__ == "__main__":
threads = []
for i in xrange(5):
threads.append(threading.Thread(target=worker,args=(i,)))
for t in threads:
t.start()
#t.join() #阻塞子线程 #t.join() #阻塞父线程 end = time.clock()
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个子线程分别刚被t.start()之后,立即把自身阻塞了,所以它们会按序执行,同样,程序sleep了5秒,一定要注意,你这样做,程序的效率并没有提升,仍然需要5秒的时间。所以这样是有问题的,问题出在t.join()代码放的位置,应该再 for t in threads: t.join(),使得这些线程同时start,然后同时join()。
-------> 同样代码,当阻塞父线程时,输出如下:
worker 0
worker 1
worker 2
worker 3
worker 4
finished: 1.003s
这里,阻塞父线程,父线程会等待子线程结束,才会继续运行打印finished,程序的效率也得到了提升。这相当于上面提到的,先把所有的子线程start了,再join掉。
3、关于setDaemon()方法
setDaemon()方法是设置在子线程中的,当我们在父线程A中创建了n个子线程之后,给我们喜欢的子线程设置setDaemon(True)后,当它们的父线程运行结束之后,不管这些子线程运行结束还是没结束,它会直接结束程序。这里,还有一个需要注意的,setDaemon()方法必须设置在start()方法之前,否则会抛RuntimeError异常。
还用上面的例子:
# -*- coding:utf-8 -*-
import Queue,time,threading
start = time.clock() def worker(m):
print 'worker',m
time.sleep(1)
return if __name__ == "__main__":
threads = []
for i in xrange(5):
threads.append(threading.Thread(target=worker,args=(i,)))
for t in threads:
t.setDaemon(True)
t.start()
#t.join() #阻塞子线程 #t.join() #阻塞父线程 end = time.clock()
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()方法,实现子线程要执行的内容,例如:
# -*- coding:utf-8 -*-
__author__ = 'webber'
import threading,time class Mythread(threading.Thread): def __init__(self,m):
threading.Thread.__init__(self)
self.m = m def run(self):
print 'worker', self.m
time.sleep(1)
return if __name__ == "__main__":
start = time.clock() threads = []
for i in xrange(5):
threads.append(Mythread(i))
for t in threads:
t.start() t.join()
end = time.clock()
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() #释放这把锁
下面有个代码应用小例子:
# -*- coding:utf-8 -*-
__author__ = 'webber'
import threading, time, random dish = 0
lock = threading.Lock() def producerFunction():
'''如果投的筛子比0.5大,则向盘子中增加一个苹果'''
global lock, dish
while dish < 10:
if (random.random() > 0.5):
lock.acquire()
dish += 1
print('生产者增加了一个苹果,现在有%d个苹果' % (dish,))
lock.release()
time.sleep(random.random() * 3) def consumerFunction():
'''如果投的筛子比0.5小,则从盘子中取一个苹果'''
global lock, dish
while dish > 0:
if (random.random() < 0.5):
lock.acquire()
dish -= 1
print('消费者拿走一个苹果现,现在有%d个苹果' % (dish,))
lock.release()
time.sleep(random.random() * 3) def begin():
ident1 = threading.Thread(target=producerFunction())
ident2 = threading.Thread(target=consumerFunction())
ident1.start()
ident2.start() if __name__ == '__main__':
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
再看python多线程------threading模块的更多相关文章
- Python(多线程threading模块)
day27 参考:http://www.cnblogs.com/yuanchenqi/articles/5733873.html CPU像一本书,你不阅读的时候,你室友马上阅读,你准备阅读的时候,你室 ...
- python中threading模块详解(一)
python中threading模块详解(一) 来源 http://blog.chinaunix.net/uid-27571599-id-3484048.html threading提供了一个比thr ...
- python多线程threading.Lock锁用法实例
本文实例讲述了python多线程threading.Lock锁的用法实例,分享给大家供大家参考.具体分析如下: python的锁可以独立提取出来 mutex = threading.Lock() #锁 ...
- Python:多线程threading模块
目录 Thread对象 Lock对象 local对象 Thread对象: 多任务可以由多进程完成,也可以由一个进程内的多线程完成.进程是由至少1个线程组成的. threading模块在较低级的模块 _ ...
- python编程中的并发------多线程threading模块
任务例子:喝水.吃饭动作需要耗时1S 单任务:(耗时20s) for i in range(10): print('a正在喝水') time.sleep(1) print('a正在吃饭') time. ...
- 学会使用Python的threading模块、掌握并发编程基础
threading模块 Python中提供了threading模块来实现线程并发编程,官方文档如下: 官方文档 添加子线程 实例化Thread类 使用该方式新增子线程任务是比较常见的,也是推荐使用的. ...
- [转]python 多线程threading简单分析
多线程和多进程是什么自行google补脑 对于python 多线程的理解,我花了很长时间,搜索的大部份文章都不够通俗易懂.所以,这里力图用简单的例子,让你对多线程有个初步的认识. 单线程 在好些年前的 ...
- 多线程threading模块
python的多线程编程 简介 多线程编程技术可以实现代码并行性,优化处理能力,同时功能的更小划分可以使代码的可重用性更好.Python中threading和Queue模块可以用来实现多线程编程. 详 ...
- Python多线程 - threading
目录 1. GIL 2. API 3. 创建子线程 4. 线程同步 4.1. 有了GIL,是否还需要同步? 4.1.1. 死锁 4.1.2. 竞争条件 4.1.3. GIL去哪儿了 4.2. Lock ...
随机推荐
- hihoCoder #1586 : Minimum-结构体版线段树(单点更新+区间最值求区间两数最小乘积) (ACM-ICPC国际大学生程序设计竞赛北京赛区(2017)网络赛)
#1586 : Minimum Time Limit:1000ms Case Time Limit:1000ms Memory Limit:256MB Description You are give ...
- Web模糊测试工具Powerfuzzer
Web模糊测试工具Powerfuzzer Powerfuzzer是Kali Linux自带的一款Web模糊测试工具.该工具基于各种开源模糊测试工具构建,集成了大量安全信息.该工具高度智能化,它能根 ...
- Word Pattern - LeetCode
Given a pattern and a string str, find if str follows the same pattern. Here follow means a full mat ...
- 使用LeakCanary遇到的问题 就是不弹出来
今天楼主遇到引用LeakCanary时代码跟官网一样但是就不弹出来.楼主新建项目就可以正常使用.楼主郁闷半天,现在终于整出来了. 楼主主工程app引用module为thirdParty,本想为了整洁三 ...
- php+mysql两次左外联跨表查询
代码如下: $querySel="select * from roomsy rsy left join room ro on rsy.RoomID=ro.ID left join hotel ...
- 真正解决 thinkphp 验证码 出错 无法显示 问题
今天做到验证码这一块想到tp自带验证图片 大喜单鼓捣半天不出来 一直是个小 X 官方提示:如果无法显示验证码,请检查:² PHP是否已经安装GD库支持:²输出之前是否有任何的输出(尤其是UTF8的B ...
- SilverLight-DataBinding-DataTemplates: 三、数据绑定 DataTemplates模板的使用(求助,没有到达实例效果,求高人指点迷津)
ylbtech-SilverLight-DataBinding-DataTemplates: 三.数据绑定 DataTemplates模板的使用 1.A, Data Templates Intro(数 ...
- 简单便捷的纯PHP网盘程序 Veno File Manager 2.6.3(VFM2)
体验过很多国外网盘程序,例如:Owncloud.Bedrive.YetiShare.XFilesharing.uCloud.Cloudshare 等等,诸如此类,VFM2与这些臃肿的商用或非商用来的程 ...
- bbed初体验
bbed能够直接查看或改动数据文件.听起来非常强大,以下体验一下,安装方法网上一搜一大把,我的环境是centos+10G的 bbed參考文档:http://pan.baidu.com/s/1hqCC6 ...
- CentOS---网络配置具体解释
一.配置文件具体解释 在RHEL或者CentOS等Redhat系的Linux系统里.跟网络有关的主要设置文件例如以下: /etc/host.conf 配置域名服务client的控制文件 ...