之前我们已经学会如何在代码块中创建新的线程去执行我们要同步执行的多个任务,但是线程的世界远不止如此。接下来,我们要介绍的是整个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——线程与多线程进阶的更多相关文章

  1. python——线程与多线程基础

    我们之前已经初步了解了进程.线程与协程的概念,现在就来看看python的线程.下面说的都是一个进程里的故事了,暂时忘记进程和协程,先来看一个进程中的线程和多线程.这篇博客将要讲一些单线程与多线程的基础 ...

  2. python 线程、多线程

    复习进程知识: python:主进程,至少有一个主线程 启动一个新的子进程:Process,pool 给每一个进程设定一下执行的任务:传一个函数+函数的参数 如果是进程池:map函数:传入一个任务函数 ...

  3. 第 11 章 python线程与多线程

    一.什么是线程 在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程. 进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合),而线程才是cpu上的执行单位. 多线程(即多 ...

  4. 在python中单线程,多线程,多进程对CPU的利用率实测以及GIL原理分析

    首先关于在python中单线程,多线程,多进程对cpu的利用率实测如下: 单线程,多线程,多进程测试代码使用死循环. 1)单线程: 2)多线程: 3)多进程: 查看cpu使用效率: 开始观察分别执行时 ...

  5. Python中的多线程编程,线程安全与锁(二)

    在我的上篇博文Python中的多线程编程,线程安全与锁(一)中,我们熟悉了多线程编程与线程安全相关重要概念, Threading.Lock实现互斥锁的简单示例,两种死锁(迭代死锁和互相等待死锁)情况及 ...

  6. Python中的多线程编程,线程安全与锁(一)

    1. 多线程编程与线程安全相关重要概念 在我的上篇博文 聊聊Python中的GIL 中,我们熟悉了几个特别重要的概念:GIL,线程,进程, 线程安全,原子操作. 以下是简单回顾,详细介绍请直接看聊聊P ...

  7. python基础-12 多线程queue 线程交互event 线程锁 自定义线程池 进程 进程锁 进程池 进程交互数据资源共享

    Python中的进程与线程 学习知识,我们不但要知其然,还是知其所以然.你做到了你就比别人NB. 我们先了解一下什么是进程和线程. 进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CP ...

  8. 第十章:Python高级编程-多线程、多进程和线程池编程

    第十章:Python高级编程-多线程.多进程和线程池编程 Python3高级核心技术97讲 笔记 目录 第十章:Python高级编程-多线程.多进程和线程池编程 10.1 Python中的GIL 10 ...

  9. python高级之多线程

    python高级之多线程 本节内容 线程与进程定义及区别 python全局解释器锁 线程的定义及使用 互斥锁 线程死锁和递归锁 条件变量同步(Condition) 同步条件(Event) 信号量 队列 ...

随机推荐

  1. FC400A与400B的区别

    FC400B就比400A多了一个功能,那就是联动,也就是说主机关了后,电子净化箱也会被关掉,这样就不需要去手动关闭电源,更加方便,估计是很多工业企业上需要这样的功能,所以就升级了这么个版本.

  2. TCP/IP协议与UDP协议的区别

    TCP(Transmission Control Protocol,传输控制协议)是面向连接的协议,也就是说,在收发数据前,必须和对方建立可靠的连接.一个TCP连接必须要经过三次“对话”才能建立起来, ...

  3. jquery 提交From表单

    /** * 异步提交From */ function ajaxSubmitFrom (btnId,fromId,url){ $(btnId).click(function () { var optio ...

  4. python:模态编程框

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...

  5. sqllite 默认当前日期写法

    create table IF NOT EXISTS realpoint(_id integer primary key autoincrement,rountId varchar(50),lng d ...

  6. xcopy /r /y "$(TargetPath)" "$(ProjectDir)"..\CMSAdmin\DLL\

    作用:1.所有都生成这里容易管理 2.tfs获取的时候不会有出问题 3.如果都是引用项目 会存在先后顺序 也会导致生成代码的时候出问题

  7. java udp与tcp

    一:基础  NET基本对象java.net.InetAddress类的使用 IP地址是IP使用的32位(IPv4)或者128位(IPv6)位无符号数字,它是传输层协议TCP,UDP的基础.InetAd ...

  8. 《利用python进行数据分析》读书笔记--第六章 数据加载、存储与文件格式

    http://www.cnblogs.com/batteryhp/p/5021858.html 输入输出一般分为下面几类:读取文本文件和其他更高效的磁盘存储格式,加载数据库中的数据.利用Web API ...

  9. Nginx与Lua利用fpm打成rpm包

    1.下载相关软件 需要软件有:Nginx,LuaJIT,ngx_devel_kit,ngx_lua等安装文件 安装Lua或者LuaJIT都是可以的,但是出于效率的考虑,推荐安装LuaJITshell& ...

  10. linux 脚本小试系列

    实现100以内的奇数和和偶数和的脚本 1 #!/bin/bash 2 # #声明一个偶数变量和一个奇数变量 3 declare -i evensum=0 4 declare -i oddsum=0 # ...