python——线程与多线程进阶
之前我们已经学会如何在代码块中创建新的线程去执行我们要同步执行的多个任务,但是线程的世界远不止如此。接下来,我们要介绍的是整个threading模块。threading基于Java的线程模型设计。锁(Lock)和条件变量(Condition)在Java中是对象的基本行为(每一个对象都自带了锁和条件变量),而在Python中则是独立的对象,所以python的threading模块中还提供了Lock,Rlock,Condition,Event等常用类,它们在python中是独立于Tread模块的,但是却与线程紧密相关,不可分割。
需要注意的是:python的线程中没有优先级、线程组,也不能被停止、暂停、恢复、中断,线程只能随着线程中的代码执行完毕而被销毁。查了n多资料之后终于接受了以上事实,个人觉得这是python的一个坑,导致了我在实现线程池的时候无法停止已经注入了方法且执行超时的线程。
threading模块提供的类:
Thread, Lock, Rlock, Condition, [Bounded]Semaphore, Event, Timer, local.
threading 模块提供的常用方法:
threading.currentThread(): 返回当前的线程变量。
threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
threading模块常用类详解
Thread类:我们使用Thread类来创建新的线程
- start 线程准备就绪,等待CPU调度
- setName 为线程设置名称
- getName 获取线程名称
- setDaemon 设置为后台线程或前台线程(默认)
如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,均停止
如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止 - join 逐个执行每个线程,执行完毕后继续往下执行,该方法是有高级用法的,代码在下面
- run 线程被cpu调度后执行Thread类对象的run方法
import time
import threading def printNum(a):
print 'num:',a
time.sleep(1) def ThreadTest(i):
return threading.Thread(target=printNum, args=(999,)) thread_arr = []
for i in range(10):
t = ThreadTest(i)
thread_arr.append(t) for t in thread_arr:
t.start() for t in thread_arr:
t.join() print 'finished'
join进阶用法
Lock类和Rlock类:由于线程之间随机调度:某线程可能在执行n条后,CPU接着执行其他线程。为了多个线程同时操作一个内存中的资源时不产生混乱,我们使用锁
- acquire 给线程上锁
- release 给线程解锁

无论是lock还是rlock,提供的方法都非常简单,acquire和release。但是rlock和lock的区别是什么呢?RLock允许在同一线程中被多次acquire。而Lock却不允许这种情况。注意:如果使用RLock,那么acquire和release必须成对出现,即调用了n次acquire,必须调用n次的release才能真正释放所占用的锁。
#!/usr/bin/env python
#-*-coding:utf-8-*-
__author__ = 'Eva_J' 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()
lock vs rlock Code
Condition类:条件变量对象能让一个线程停下来,等待其它线程满足了某个“条件”。如,状态的改变或值的改变。
- acquire 给线程上锁
- wait wait方法释放当前线程占用的锁,同时挂起线程,直至被唤醒或超时(需timeout参数)。当线程被唤醒并重新占有锁的时候,程序才会继续执行下去。
- notify 唤醒一个挂起的线程(如果存在挂起的线程)。注:notify()方法不会释放所占用的锁。
- notifyall 调用这个方法将通知等待池中所有线程,这些线程都将进入锁定池尝试获得锁定。此方法不会释放锁定。使用前线程必须已获得锁定,否则将抛出异常。
比较经典的例子是下面这个生产者与消费者的例子,这个例子网上一搜到处都是,这里简单解释一下这段代码的意义,代码中写了两个类,Consumer和Producer,分别继承了Thread类,我们分别初始化这两个类获得了c和p对象,并启动这两个线程。则这两个线程去执行run方法(这里与Thread类内部的调度有关),定义了producer全局变量和condition对象为全局变量,当producer不大于1时,消费者线程被condition对象阻塞,不能继续消费(这里是不再递减),当producer不小于10时,生产者线程被condition对象阻塞,不再生产(这里是不再累加),代码在下面,拿去执行,断点一下就明白了。
#!/usr/bin/env python
#-*-coding:utf-8-*-
__author__ = 'Eva_J' import threading
import time condition = threading.Condition()
products = 0 class Producer(threading.Thread):
def __init__(self):
threading.Thread.__init__(self) def run(self):
global condition, products
while True:
if condition.acquire():
if products < 10:
products += 1;
print "Producer(%s):deliver one, now products:%s" %(self.name, products)
condition.notify()
else:
print "Producer(%s):already 10, stop deliver, now products:%s" %(self.name, products)
condition.wait();
condition.release()
time.sleep(2) class Consumer(threading.Thread):
def __init__(self):
threading.Thread.__init__(self) def run(self):
global condition, products
while True:
if condition.acquire():
if products > 1:
products -= 1
print "Consumer(%s):consume one, now products:%s" %(self.name, products)
condition.notify()
else:
print "Consumer(%s):only 1, stop consume, products:%s" %(self.name, products)
condition.wait();
condition.release()
time.sleep(2) if __name__ == "__main__":
for p in range(0, 2):
p = Producer()
p.start() for c in range(0, 10):
c = Consumer()
c.start()
condition Code
Event类:通用的条件变量。多个线程可以等待某个事件的发生,在事件发生后,所有的线程都会被激活。
- event.wait(timeout) 当Flag为‘False’时,线程将被阻塞
- clear 将“Flag”设置为False
- set 将“Flag”设置为True
- is_set 返回当前‘Flag’
这是一个比较关键的类,我在写线程池的时候看到python的threadpool模块也用到了。它的意义在于可以控制属于同一个线程类的多个实例化对象,让他们同时阻塞或者执行。配合队列来实现一个线程池非常好用。在接下里的博客中我们还要继续介绍。先放一个小例子在这里练练手,了解一下event的用法。
#!/usr/bin/env python
#-*-coding:utf-8-*-
__author__ = 'Eva_J' import threading
import time event = threading.Event() def func():
# 等待事件,进入等待阻塞状态
print '%s wait for event...' % threading.currentThread().getName()
event.wait() # 收到事件后进入运行状态
print '%s recv event.' % threading.currentThread().getName() t1 = threading.Thread(target=func)
t2 = threading.Thread(target=func)
t1.start()
t2.start() time.sleep(2) # 发送事件通知
print 'MainThread set event.'
event.set()
event Code
参考文献:
python多线程学习小结:http://www.myexception.cn/perl-python/1688021.html
python线程指南:http://www.cnblogs.com/huxi/archive/2010/06/26/1765808.html
threading.RLock和threading.Lock:http://blog.sina.com.cn/s/blog_5dd2af0901012rad.html
python的进程、线程与协程:http://www.cnblogs.com/wupeiqi/articles/5040827.html
python——线程与多线程进阶的更多相关文章
- python——线程与多线程基础
我们之前已经初步了解了进程.线程与协程的概念,现在就来看看python的线程.下面说的都是一个进程里的故事了,暂时忘记进程和协程,先来看一个进程中的线程和多线程.这篇博客将要讲一些单线程与多线程的基础 ...
- python 线程、多线程
复习进程知识: python:主进程,至少有一个主线程 启动一个新的子进程:Process,pool 给每一个进程设定一下执行的任务:传一个函数+函数的参数 如果是进程池:map函数:传入一个任务函数 ...
- 第 11 章 python线程与多线程
一.什么是线程 在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程. 进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合),而线程才是cpu上的执行单位. 多线程(即多 ...
- 在python中单线程,多线程,多进程对CPU的利用率实测以及GIL原理分析
首先关于在python中单线程,多线程,多进程对cpu的利用率实测如下: 单线程,多线程,多进程测试代码使用死循环. 1)单线程: 2)多线程: 3)多进程: 查看cpu使用效率: 开始观察分别执行时 ...
- Python中的多线程编程,线程安全与锁(二)
在我的上篇博文Python中的多线程编程,线程安全与锁(一)中,我们熟悉了多线程编程与线程安全相关重要概念, Threading.Lock实现互斥锁的简单示例,两种死锁(迭代死锁和互相等待死锁)情况及 ...
- Python中的多线程编程,线程安全与锁(一)
1. 多线程编程与线程安全相关重要概念 在我的上篇博文 聊聊Python中的GIL 中,我们熟悉了几个特别重要的概念:GIL,线程,进程, 线程安全,原子操作. 以下是简单回顾,详细介绍请直接看聊聊P ...
- python基础-12 多线程queue 线程交互event 线程锁 自定义线程池 进程 进程锁 进程池 进程交互数据资源共享
Python中的进程与线程 学习知识,我们不但要知其然,还是知其所以然.你做到了你就比别人NB. 我们先了解一下什么是进程和线程. 进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CP ...
- 第十章:Python高级编程-多线程、多进程和线程池编程
第十章:Python高级编程-多线程.多进程和线程池编程 Python3高级核心技术97讲 笔记 目录 第十章:Python高级编程-多线程.多进程和线程池编程 10.1 Python中的GIL 10 ...
- python高级之多线程
python高级之多线程 本节内容 线程与进程定义及区别 python全局解释器锁 线程的定义及使用 互斥锁 线程死锁和递归锁 条件变量同步(Condition) 同步条件(Event) 信号量 队列 ...
随机推荐
- ios webView 放大网页解决/input 获得焦点focus 网页放大 解决
新手遇到的问题: 终于找到原因,各种HTML viewport 都试过 setScalePageToFit 也试过,webViewDidFinishLoad加JS代码,动态算webView.scrol ...
- MySql SELECT INTO 记录为空的问题
SELECT Id INTO @Id FROM GiftCode WHERE Status = 1 AND GiftId = #GiftId# ORDER BY Id ASC LIMIT 1; ...
- python 实现简单 http 代理
有台 openwrt 路由器,16M flash存储 + 64M 内存 ,可以装 python .因为没有自带 url 网站访问记录,想手写一个. 原理: http 1.1 也就是 tcp 连接,有 ...
- jquery常用插件及用法总结
http://www.jb51.net/Special/200.htm
- C++中的4个类型转换关键字
转载:http://poplars.blog.163.com/blog/static/1394221742013021111210567/ n多书里面推荐要养成使用转型关键字的习惯,几年过去了,感觉还 ...
- IDEA UTF-8 中含 bom 运行报错 批量处理将bom移除
将eclipse中的项目导入到idea或者as的环境中,遇到UTF-8含有BOM编码报错的问题,之前每次遇到这样的问题都特么用EditPlus一个一个的转换,感觉太烦了,后面就自己写了一个批量处理的工 ...
- Tomcat去除项目名称和端口号,直接使用ip地址访问项目的方法
网站开发过程中,一般的工程访问路径是 http://112.74.51.37/projectName如何设置成http://112.74.51.37/ 解决方法: 首先,进入tomcat的安装目录下的 ...
- JAVA基础知识之Annotation
基本Annotation Annotation必须使用工具(APT, Annotation tool)才能处理,Annotation可以在编译,类加载,运行时被读取,并执行相应处理. 下面介绍一些常用 ...
- 关于C语言宏定义 使用do{ xxxx }while()
暂时感觉像是由于":"的原因,关于使用习惯方面的问题!! 下面是copy的: 这样的宏见过么: Cpp代码 #define FOO(x) do {\ some_code_line_ ...
- 20161127-adt bundle
1.adt.exe 路径:E:\software\adt-bundle-windows-x86-20131030\sdk\platform-tools\adt.exe 配置环境变量 命令: adb d ...