python中的多线程实例教程


Posted in Python onAugust 27, 2014

本文以实例形式较为详细的讲述了Python中多线程的用法,在Python程序设计中有着比较广泛的应用。分享给大家供大家参考之用。具体分析如下:

python中关于多线程的操作可以使用thread和threading模块来实现,其中thread模块在Py3中已经改名为_thread,不再推荐使用。而threading模块是在thread之上进行了封装,也是推荐使用的多线程模块,本文主要基于threading模块进行介绍。在某些版本中thread模块可能不存在,要使用dump_threading来代替threading模块。

一、线程创建

threading模块中每个线程都是一个Thread对象,创建一个线程有两种方式,一种是将函数传递到Thread对象中执行,另一种是从Thread继承,然后重写run方法(是不是跟Java很像)。

下面使用这两种方法分别创建一个线程并同时执行

import random, threading
def threadFunction():
  for i in range(10):
    print 'ThreadFuction - %d'%i
    time.sleep(random.randrange(0,2))


class ThreadClass(threading.Thread):
  def __init__(self):
    threading.Thread.__init__(self);
    
  def run(self):
    for i in range(10):
      print 'ThreadClass - %d'%i
      time.sleep(random.randrange(0,2))

if __name__ == '__main__':
  tFunc = threading.Thread(target = threadFunction);
  tCls = ThreadClass()
  tFunc.start()
  tCls.start()

执行结果如下,可以看到两个线程在交替打印。至于空行和一行多个输出,是因为Py的print并不是线程安全的,在当前线程的print打印了部分内容后,准备打印换行之前,被别的线程中的print抢先,在换行之前打印了其它的内容。

ThreadFuction - 0
ThreadFuction - 1
ThreadFuction - 2
ThreadClass - 0
ThreadFuction - 3
ThreadClass - 1
ThreadFuction - 4
ThreadClass - 2
ThreadClass - 3
ThreadClass - 4ThreadFuction - 5

ThreadClass - 5
ThreadClass - 6
ThreadClass - 7
ThreadClass - 8
ThreadFuction - 6ThreadClass - 9

ThreadFuction - 7
ThreadFuction - 8
ThreadFuction - 9

Thread类的构造函数定义如下

class threading.Thread(group=None, target=None, name=None, args=(), kwargs={})

group: 留作ThreadGroup扩展使用,一般没什么用
target:新线程的任务函数名
name:  线程名,一般也没什么用
args:  tuple参数
kwargs:dictionary参数

Thread类的成员变量和函数如下

start()         启动一个线程
run()           线程执行体,也是一般要重写的内容
join([timeout]) 等待线程结束
name            线程名
ident           线程ID
daemon          是否守护线程
isAlive()、is_alive()    线程是否存活
getName()、setName()     Name的get&set方法
isDaemon()、setDaemon()  daemon的get&set方法

这里的守护线程与Linux中的守护进程并不是一个概念。这里是指当所有守护线程退出后主程序才会退出,否则即使线程任务没有结束,只要不是守护线程,都会跟着主程序一起退出。而Linux中的守护进程定义正好相反,守护进程已经脱离父进程,不会随着父进程的结束而退出。

二、线程同步

线程同步是多线程中的一个核心问题,threading模块对线程同步有着良好的支持、包括线程特定数据、信号量、互斥锁、条件变量等

1.线程特定数据

简而言之,线程特定数据就是线程独自持有的全局变量,相互之间的修改不会造成影响。

threading模块中使用local()方法生成一个线程独立对象,举例如下,其中sleep(1)是为了保证让子线程先运行完再运行接下来的语句。

data = threading.local()
def threadFunction():
  global data
  data.x = 3
  print threading.currentThread(), data.x
  
if __name__ == '__main__':
  data.x = 1
  tFunc = threading.Thread(target = threadFunction).start();
  time.sleep(1)
  print threading.current_thread(), data.x
<Thread(Thread-1, started 36208)> 3
<_MainThread(MainThread, started 35888)> 1

输出如上,可以看到,Thread-1中对data.x的修改并没有影响到主线程中data.x的值。

2.互斥锁

threading中定义了两种锁:threading.Lock和threading.RLock。两者的不同在于后者是可重入锁,也就是说在一个线程内重复LOCK同一个锁不会发生死锁,这与POSIX中的PTHREAD_MUTEX_RECURSIVE也就是可递归锁的概念是相同的。

关于互斥锁的API很简单,只有三个函数————分配锁,上锁,解锁。

threading.Lock()        分配一个互斥锁
acquire([blocking=1])   上锁(阻塞或者非阻塞,非阻塞时相当于try_lock,通过返回False表示已经被其它线程锁住。)
release()               解锁
下面通过一个例子来说明互斥锁的使用。在之前的例子中,多线程print会造成混乱的输出,这里使用一个互斥锁,来保证每行一定只有一个输出。

def threadFunction(arg):
  while True:
    lock.acquire()
    print 'ThreadFuction - %d'%arg
    lock.release()

if __name__ == '__main__':
  lock = threading.Lock()
  threading.Thread(target = threadFunction, args=(1,)).start();
  threading.Thread(target = threadFunction, args=(2,)).start();

3.条件变量

条件变量总是与互斥锁一起使用的,threading中的条件变量默认绑定了一个RLock,也可以在初始化条件变量的时候传进去一个自己定义的锁。

可用的函数如下

threading.Condition([lock]) 分配一个条件变量
acquire(*args)        条件变量上锁
release()          条件变量解锁
wait([timeout])       等待唤醒,timeout表示超时
notify(n=1)         唤醒最大n个等待的线程
notifyAll()、notify_all()  唤醒所有等待的线程
下面这个例子使用条件变量来控制两个线程交替运行

num = 0
def threadFunction(arg):
  global num
  while num < 10:
    cond.acquire()
    while num % 2 != arg:
      cond.wait()
    print 'Thread %d - %d' %(arg, num)
    num += 1
    cond.notify()
    cond.release()

if __name__ == '__main__':
  cond = threading.Condition()
  threading.Thread(target = threadFunction, args=(0,)).start();
  threading.Thread(target = threadFunction, args=(1,)).start();

输出如下

Thread 0 - 0
Thread 1 - 1
Thread 0 - 2
Thread 1 - 3
Thread 0 - 4
Thread 1 - 5
Thread 0 - 6
Thread 1 - 7
Thread 0 - 8
Thread 1 - 9
Thread 0 - 10

其实上面这个程序是有问题的,我们想打印的是0~9,但实际上10也被打印了出来,原因很简单,因为两个线程交替打印,使得num在一个线程中可能加2,从而导致10被打印出来,所以必须在打印前再次check。

相信本文所述对大家的Python程序设计有一定的借鉴价值。

Python 相关文章推荐
Python字符串处理实例详解
May 18 Python
scrapy spider的几种爬取方式实例代码
Jan 25 Python
深入浅析python 中的匿名函数
May 21 Python
浅析Python pandas模块输出每行中间省略号问题
Jul 03 Python
python之super的使用小结
Aug 13 Python
tensorflow实现加载mnist数据集
Sep 08 Python
Python3实现腾讯云OCR识别
Nov 27 Python
python2.7使用plotly绘制本地散点图和折线图
Apr 02 Python
详解python解压压缩包的五种方法
Jul 05 Python
Python中类似于jquery的pyquery库用法分析
Dec 02 Python
Pytorch基本变量类型FloatTensor与Variable用法
Jan 08 Python
class类在python中获取金融数据的实例方法
Dec 10 Python
闭包在python中的应用之translate和maketrans用法详解
Aug 27 #Python
web.py获取上传文件名的正确方法
Aug 26 #Python
Python version 2.7 required, which was not found in the registry
Aug 26 #Python
web.py中调用文件夹内模板的方法
Aug 26 #Python
web.py在模板中输出美元符号的方法
Aug 26 #Python
Django1.3添加app提示模块不存在的解决方法
Aug 26 #Python
Python引用(import)文件夹下的py文件的方法
Aug 26 #Python
You might like
php str_pad 函数用法简介
2009/07/11 PHP
CodeIgniter辅助之第三方类库third_party用法分析
2016/01/20 PHP
Zend Framework教程之模型Model基本规则和使用方法
2016/03/04 PHP
php如何控制用户对图片的访问 PHP禁止图片盗链
2016/03/25 PHP
[原创]php正则删除img标签的方法示例
2017/05/27 PHP
浅谈PHP接入(第三方登录)QQ登录 OAuth2.0 过程中遇到的坑
2017/10/13 PHP
Laravel框架实现抢红包功能示例
2019/10/31 PHP
通过百度地图获取公交线路的站点坐标的js代码
2012/05/11 Javascript
UpdatePanel和Jquery冲突的解决方法
2013/04/01 Javascript
为指定的元素添加遮罩层的示例代码
2014/01/15 Javascript
SpringMVC框架下JQuery传递并解析Json格式的数据是如何实现的
2015/12/10 Javascript
jQuery实现表格行和列的动态添加与删除方法【测试可用】
2016/08/01 Javascript
bootstrap table操作技巧分享
2017/02/15 Javascript
JS实现禁止高频率连续点击的方法【基于ES6语法】
2017/04/25 Javascript
Js实现中国公民身份证号码有效性验证实例代码
2017/05/03 Javascript
vue.js的computed,filter,get,set的用法及区别详解
2018/03/08 Javascript
JS与CSS3实现图片响应鼠标移动放大效果示例
2018/05/04 Javascript
jQuery实现输入框的放大和缩小功能示例
2018/07/21 jQuery
微信小程序日历/日期选择插件使用方法详解
2018/12/28 Javascript
细述Javascript的加法运算符的具体使用
2019/10/18 Javascript
Python简单删除目录下文件以及文件夹的方法
2015/05/27 Python
python 统计数组中元素出现次数并进行排序的实例
2018/07/02 Python
Python实现曲线拟合操作示例【基于numpy,scipy,matplotlib库】
2018/07/12 Python
pygame游戏之旅 游戏中添加显示文字
2018/11/20 Python
python使用pandas处理excel文件转为csv文件的方法示例
2019/07/18 Python
详细介绍Python进度条tqdm的使用
2019/07/31 Python
python os.path.isfile()因参数问题判断错误的解决
2019/11/29 Python
python中zip()函数遍历多个列表方法
2021/02/18 Python
Html5实现如何在两个div元素之间拖放图像
2013/03/29 HTML / CSS
一份Java笔试题
2012/02/21 面试题
优秀干部获奖感言
2014/01/31 职场文书
学生周末回家住宿长期请假条
2014/02/15 职场文书
《翻越远方的大山》教学反思
2014/04/13 职场文书
小公司融资,商业计划书的8切记
2019/07/15 职场文书
python数字图像处理实现图像的形变与缩放
2022/06/28 Python