热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Python多线程使用总结

threading用于提供线程相关的操作,线程是应用程序中工作的最小单元。python当前版本的多线程库没有实现优先级、线程组,线程也不能被停止、暂停、

threading用于提供线程相关的操作,线程是应用程序中工作的最小单元。python当前版本的多线程库没有实现优先级、线程组,线程也不能被停止、暂停、恢复、中断。

threading模块提供的类:  
  Thread, Lock, Rlock, Condition, [Bounded]Semaphore, Event, Timer, local。

threading 模块提供的常用方法: 
  threading.currentThread(): 返回当前的线程变量。 
  threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。 
  threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

threading 模块提供的常量:

  threading.TIMEOUT_MAX 设置threading全局超时时间。

 

Thread类



 

Thread是线程类,有两种使用方法,直接传入要运行的方法或从Thread继承并覆盖run():

# coding:utf-8
import threading
import time
#方法一:将要执行的方法作为参数传给Thread的构造方法
def action(arg):time.sleep(1)print 'the arg is:%s\r' %argfor i in xrange(4):t =threading.Thread(target=action,args=(i,))t.start()print 'main thread end!'#方法二:从Thread继承,并重写run()
class MyThread(threading.Thread):def __init__(self,arg):super(MyThread, self).__init__()#注意:一定要显式的调用父类的初始化函数。self.arg=argdef run(self):#定义每个线程要运行的函数time.sleep(1)print 'the arg is:%s\r' % self.argfor i in xrange(4):t =MyThread(i)t.start()print 'main thread end!'

 

构造方法: 
Thread(group=None, target=None, name=None, args=(), kwargs={}) 

  group: 线程组,目前还没有实现,库引用中提示必须是None; 
  target: 要执行的方法; 
  name: 线程名; 
  args/kwargs: 要传入方法的参数。

实例方法: 
  isAlive(): 返回线程是否在运行。正在运行指启动后、终止前。 

  get/setName(name): 获取/设置线程名。 

  start():  线程准备就绪,等待CPU调度
  is/setDaemon(bool): 获取/设置是后台线程(默认前台线程(False))。(在start之前设置)

    如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,主线程和后台线程均停止
         如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止
  start(): 启动线程。 
  join([timeout]): 阻塞当前上下文环境的线程,直到调用此方法的线程终止或到达指定的timeout(可选参数)。

 

使用例子一(未设置setDeamon): 

 

# coding:utf-8
import threading
import timedef action(arg):time.sleep(1)print 'sub thread start!the thread name is:%s\r' % threading.currentThread().getName()print 'the arg is:%s\r' %argtime.sleep(1)for i in xrange(4):t =threading.Thread(target=action,args=(i,))t.start()print 'main_thread end!'


 

main_thread end!
sub thread start!the thread name
is:Thread-2
the arg
is:1
the arg
is:0
sub thread start!the thread name
is:Thread-4
the arg
is:2
the arg
is:3
Process finished with exit code 0
可以看出,创建的4个“前台”线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止


验证了serDeamon(False)(默认)前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,主线程停止。

 

使用例子二(setDeamon=True)

# coding:utf-8
import threading
import timedef action(arg):time.sleep(1)print 'sub thread start!the thread name is:%s\r' % threading.currentThread().getName()print 'the arg is:%s\r' %argtime.sleep(1)for i in xrange(4):t =threading.Thread(target=action,args=(i,))t.setDaemon(True)#设置线程为后台线程
t.start()print 'main_thread end!'



main_thread end!Process finished with exit code 0可以看出,主线程执行完毕后,后台线程不管是成功与否,主线程均停止


验证了serDeamon(True)后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,主线程均停止。

 

使用例子三(设置join)

#coding:utf-8
import threading
import timedef action(arg):time.sleep(1)print 'sub thread start!the thread name is:%s ' % threading.currentThread().getName()print 'the arg is:%s ' %argtime.sleep(1)thread_list = [] #线程存放列表
for i in xrange(4):t =threading.Thread(target=action,args=(i,))t.setDaemon(True)thread_list.append(t)for t in thread_list:t.start()for t in thread_list:t.join()



sub thread start!the thread name is:Thread-2
the arg
is:1
sub thread start!the thread name
is:Thread-3
the arg
is:2
sub thread start!the thread name
is:Thread-1
the arg
is:0
sub thread start!the thread name
is:Thread-4
the arg
is:3
main_thread end!Process finished with exit code 0设置join之后,主线程等待子线程全部执行完成后或者子线程超时后,主线程才结束


验证了 join()阻塞当前上下文环境的线程,直到调用此方法的线程终止或到达指定的timeout,即使设置了setDeamon(True)主线程依然要等待子线程结束。

使用例子四(join不妥当的用法,使多线程编程顺序执行)

#coding:utf-8
import threading
import timedef action(arg):time.sleep(1)print 'sub thread start!the thread name is:%s ' % threading.currentThread().getName()print 'the arg is:%s ' %argtime.sleep(1)for i in xrange(4):t =threading.Thread(target=action,args=(i,))t.setDaemon(True)t.start()t.join()print 'main_thread end!'



sub thread start!the thread name is:Thread-1
the arg
is:0
sub thread start!the thread name
is:Thread-2
the arg
is:1
sub thread start!the thread name
is:Thread-3
the arg
is:2
sub thread start!the thread name
is:Thread-4
the arg
is:3
main_thread end!Process finished with exit code 0
可以看出此时,程序只能顺序执行,每个线程都被上一个线程的join阻塞,使得“多线程”失去了多线程意义。


 

 

Lock、Rlock类



 

  由于线程之间随机调度:某线程可能在执行n条后,CPU接着执行其他线程。为了多个线程同时操作一个内存中的资源时不产生混乱,我们使用锁。

Lock(指令锁)是可用的最低级的同步指令。Lock处于锁定状态时,不被特定的线程拥有。Lock包含两种状态——锁定和非锁定,以及两个基本的方法。

可以认为Lock有一个锁定池,当线程请求锁定时,将线程至于池中,直到获得锁定后出池。池中的线程处于状态图中的同步阻塞状态。

RLock(可重入锁)是一个可以被同一个线程请求多次的同步指令。RLock使用了“拥有的线程”和“递归等级”的概念,处于锁定状态时,RLock被某个线程拥有。拥有RLock的线程可以再次调用acquire(),释放锁时需要调用release()相同次数。

可以认为RLock包含一个锁定池和一个初始值为0的计数器,每次成功调用 acquire()/release(),计数器将+1/-1,为0时锁处于未锁定状态。

简言之:Lock属于全局,Rlock属于线程。

构造方法: 
Lock(),Rlock(),推荐使用Rlock()

实例方法: 
  acquire([timeout]): 尝试获得锁定。使线程进入同步阻塞状态。 

  release(): 释放锁。使用前线程必须已获得锁定,否则将抛出异常。

例子一(未使用锁):

#coding:utf-8
import threading
import timegl_num = 0def show(arg):global gl_numtime.sleep(1)gl_num +=1print gl_numfor i in range(10):t = threading.Thread(target=show, args=(i,))t.start()print 'main thread stop'



 运行结果

 

例子二(使用锁):

# coding:utf-8import threading
import timegl_num = 0lock = threading.RLock()# 调用acquire([timeout])时,线程将一直阻塞,
#
直到获得锁定或者直到timeout秒后(timeout参数可选)。
#
返回是否获得锁。
def Func():lock.acquire()global gl_numgl_num += 1time.sleep(1)print gl_numlock.release()for i in range(10):t = threading.Thread(target=Func)t.start()



1
2
3
4
5
6
7
8
9
10Process finished with exit code 0
可以看出,全局变量在在每次被调用时都要获得锁,才能操作,因此保证了共享数据的安全性


 

Lock对比Rlock

#coding:utf-8
import threading
lock = threading.Lock() #Lock对象
lock.acquire()
lock.acquire()  #产生了死锁。
lock.release()
lock.release()
print lock.acquire()
import threading
rLock = threading.RLock()  #RLock对象
rLock.acquire()
rLock.acquire() #在同一线程内,程序不会堵塞。
rLock.release()
rLock.release()

 

Condition类



 

  Condition(条件变量)通常与一个锁关联。需要在多个Contidion中共享一个锁时,可以传递一个Lock/RLock实例给构造方法,否则它将自己生成一个RLock实例。

  可以认为,除了Lock带有的锁定池外,Condition还包含一个等待池,池中的线程处于等待阻塞状态,直到另一个线程调用notify()/notifyAll()通知;得到通知后线程进入锁定池等待锁定。

构造方法: 
Condition([lock/rlock])

实例方法: 
  acquire([timeout])/release(): 调用关联的锁的相应方法。 

  wait([timeout]): 调用这个方法将使线程进入Condition的等待池等待通知,并释放锁。使用前线程必须已获得锁定,否则将抛出异常。 
  notify(): 调用这个方法将从等待池挑选一个线程并通知,收到通知的线程将自动调用acquire()尝试获得锁定(进入锁定池);其他线程仍然在等待池中。调用这个方法不会释放锁定。使用前线程必须已获得锁定,否则将抛出异常。 
  notifyAll(): 调用这个方法将通知等待池中所有的线程,这些线程都将进入锁定池尝试获得锁定。调用这个方法不会释放锁定。使用前线程必须已获得锁定,否则将抛出异常。

 

例子一:生产者消费者模型

# encoding: UTF-8
import threading
import time# 商品
product = None
# 条件变量
con = threading.Condition()# 生产者方法
def produce():global productif con.acquire():while True:if product is None:print 'produce...'product = 'anything'# 通知消费者,商品已经生产
con.notify()# 等待通知
con.wait()time.sleep(2)# 消费者方法
def consume():global productif con.acquire():while True:if product is not None:print 'consume...'product = None# 通知生产者,商品已经没了
con.notify()# 等待通知
con.wait()time.sleep(2)t1 = threading.Thread(target=produce)
t2
= threading.Thread(target=consume)
t2.start()
t1.start()



produce...
consume...
produce...
consume...
produce...
consume...
produce...
consume...
produce...
consume...Process finished with exit code
-1
程序不断循环运行下去。重复生产消费过程。


例子二:生产者消费者模型

import threading
import timecondition = threading.Condition()
products
&#61; 0class Producer(threading.Thread):def run(self):global productswhile True:if condition.acquire():if products <10:products &#43;&#61; 1;print "Producer(%s):deliver one, now products:%s" %(self.name, products)condition.notify()#不释放锁定&#xff0c;因此需要下面一句
condition.release()else:print "Producer(%s):already 10, stop deliver, now products:%s" %(self.name, products)condition.wait();#自动释放锁定time.sleep(2)class Consumer(threading.Thread):def run(self):global productswhile True:if condition.acquire():if products > 1:products -&#61; 1print "Consumer(%s):consume one, now products:%s" %(self.name, products)condition.notify()condition.release()else:print "Consumer(%s):only 1, stop consume, products:%s" %(self.name, products)condition.wait();time.sleep(2)if __name__ &#61;&#61; "__main__":for p in range(0, 2):p &#61; Producer()p.start()for c in range(0, 3):c &#61; Consumer()c.start()


例子三&#xff1a;

import threadingalist &#61; None
condition
&#61; threading.Condition()def doSet():if condition.acquire():while alist is None:condition.wait()for i in range(len(alist))[::-1]:alist[i] &#61; 1condition.release()def doPrint():if condition.acquire():while alist is None:condition.wait()for i in alist:print i,printcondition.release()def doCreate():global alistif condition.acquire():if alist is None:alist &#61; [0 for i in range(10)]condition.notifyAll()condition.release()tset &#61; threading.Thread(target&#61;doSet,name&#61;&#39;tset&#39;)
tprint
&#61; threading.Thread(target&#61;doPrint,name&#61;&#39;tprint&#39;)
tcreate
&#61; threading.Thread(target&#61;doCreate,name&#61;&#39;tcreate&#39;)
tset.start()
tprint.start()
tcreate.start()


 

Event类



 

  Event&#xff08;事件&#xff09;是最简单的线程通信机制之一&#xff1a;一个线程通知事件&#xff0c;其他线程等待事件。Event内置了一个初始为False的标志&#xff0c;当调用set()时设为True&#xff0c;调用clear()时重置为 False。wait()将阻塞线程至等待阻塞状态。

  Event其实就是一个简化版的 Condition。Event没有锁&#xff0c;无法使线程进入同步阻塞状态。

构造方法&#xff1a; 
Event()

实例方法&#xff1a; 
  isSet(): 当内置标志为True时返回True。 

  set(): 将标志设为True&#xff0c;并通知所有处于等待阻塞状态的线程恢复运行状态。 
  clear(): 将标志设为False。 
  wait([timeout]): 如果标志为True将立即返回&#xff0c;否则阻塞线程至等待阻塞状态&#xff0c;等待其他线程调用set()。

 

例子一

# encoding: UTF-8
import threading
import timeevent &#61; threading.Event()def func():# 等待事件&#xff0c;进入等待阻塞状态print &#39;%s wait for event...&#39; % threading.currentThread().getName()event.wait()# 收到事件后进入运行状态print &#39;%s recv event.&#39; % threading.currentThread().getName()t1 &#61; threading.Thread(target&#61;func)
t2
&#61; threading.Thread(target&#61;func)
t1.start()
t2.start()time.sleep(
2)# 发送事件通知
print &#39;MainThread set event.&#39;
event.set()


 

Thread-1 wait for event...
Thread
-2 wait for event...#2秒后。。。
MainThread set event.
Thread
-1 recv event.Thread-2 recv event.Process finished with exit code 0


 

timer类



 

  Timer&#xff08;定时器&#xff09;是Thread的派生类&#xff0c;用于在指定时间后调用一个方法。

构造方法&#xff1a; 
Timer(interval, function, args&#61;[], kwargs&#61;{}) 

  interval: 指定的时间 
  function: 要执行的方法 
  args/kwargs: 方法的参数

实例方法&#xff1a; 
Timer从Thread派生&#xff0c;没有增加实例方法。

例子一&#xff1a;

# encoding: UTF-8
import threadingdef func():print &#39;hello timer!&#39;timer &#61; threading.Timer(5, func)
timer.start()


线程延迟5秒后执行。

 

local类



 

 

  local是一个小写字母开头的类&#xff0c;用于管理 thread-local&#xff08;线程局部的&#xff09;数据。对于同一个local&#xff0c;线程无法访问其他线程设置的属性&#xff1b;线程设置的属性不会被其他线程设置的同名属性替换。

  可以把local看成是一个“线程-属性字典”的字典&#xff0c;local封装了从自身使用线程作为 key检索对应的属性字典、再使用属性名作为key检索属性值的细节。

# encoding: UTF-8
import threadinglocal &#61; threading.local()
local.tname
&#61; &#39;main&#39;def func():local.tname &#61; &#39;notmain&#39;print local.tnamet1 &#61; threading.Thread(target&#61;func)
t1.start()
t1.join()
print local.tname



notmain
main


 

参考文章链接&#xff1a;

  http://www.cnblogs.com/huxi/archive/2010/06/26/1765808.html

  http://www.cnblogs.com/wupeiqi/articles/5040827.html




推荐阅读
  • 第四章高阶函数(参数传递、高阶函数、lambda表达式)(python进阶)的讲解和应用
    本文主要讲解了第四章高阶函数(参数传递、高阶函数、lambda表达式)的相关知识,包括函数参数传递机制和赋值机制、引用传递的概念和应用、默认参数的定义和使用等内容。同时介绍了高阶函数和lambda表达式的概念,并给出了一些实例代码进行演示。对于想要进一步提升python编程能力的读者来说,本文将是一个不错的学习资料。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了C++中省略号类型和参数个数不确定函数参数的使用方法,并提供了一个范例。通过宏定义的方式,可以方便地处理不定参数的情况。文章中给出了具体的代码实现,并对代码进行了解释和说明。这对于需要处理不定参数的情况的程序员来说,是一个很有用的参考资料。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 本文介绍了如何在wxpython中将matplotlib图表嵌入到自定义窗体中的方法。通过调用FigureCanvasWx类,可以实现在自定义窗体中显示matplotlib图表。同时,还介绍了与此相关的一些类和参数。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • 展开全部下面的代码是创建一个立方体Thisexamplescreatesanddisplaysasimplebox.#Thefirstlineloadstheinit_disp ... [详细]
  • 关键词:Golang, Cookie, 跟踪位置, net/http/cookiejar, package main, golang.org/x/net/publicsuffix, io/ioutil, log, net/http, net/http/cookiejar ... [详细]
  • 本文介绍了如何使用python从列表中删除所有的零,并将结果以列表形式输出,同时提供了示例格式。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文介绍了Python语言程序设计中文件和数据格式化的操作,包括使用np.savetext保存文本文件,对文本文件和二进制文件进行统一的操作步骤,以及使用Numpy模块进行数据可视化编程的指南。同时还提供了一些关于Python的测试题。 ... [详细]
author-avatar
菜牛
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有