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对比C语言的编程思想差异
Aug 30 Python
Python教程之全局变量用法
Jun 27 Python
python实现获取Ip归属地等信息
Aug 27 Python
Python使用回溯法子集树模板解决迷宫问题示例
Sep 01 Python
Python实现KNN邻近算法
Jan 28 Python
python 在指定范围内随机生成不重复的n个数实例
Jan 28 Python
python3实现斐波那契数列(4种方法)
Jul 15 Python
详解Python利用random生成一个列表内的随机数
Aug 21 Python
python3连接kafka模块pykafka生产者简单封装代码
Dec 23 Python
Python importlib动态导入模块实现代码
Apr 16 Python
keras load model时出现Missing Layer错误的解决方式
Jun 11 Python
python反爬虫方法的优缺点分析
Nov 25 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 smarty 二级分类代码和模版循环例子
2011/06/16 PHP
php中使用addslashes函数报错问题的解决方法
2013/02/06 PHP
PHP中对缓冲区的控制实现代码
2013/09/29 PHP
php实现mysql备份恢复分卷处理的方法
2014/12/26 PHP
PHP+Apache+Mysql环境搭建教程
2016/08/01 PHP
BOOM vs RR BO5 第三场 2.14
2021/03/10 DOTA
第一个JavaScript入门基础 document.write输出
2010/02/22 Javascript
放弃用你的InnerHTML来输出HTML吧 jQuery Tmpl不详细讲解
2013/04/20 Javascript
js实现简洁的滑动门菜单(选项卡)效果代码
2015/09/04 Javascript
深入浅析JSON.parse()、JSON.stringify()和eval()的作用详解
2016/04/03 Javascript
去除字符串左右两边的空格(实现代码)
2016/05/12 Javascript
jquery 动态增加删除行的简单实例(推荐)
2016/10/12 Javascript
JS/jQuery判断DOM节点是否存在的简单方法
2016/11/24 Javascript
Nodejs 发送Post请求功能(发短信验证码例子)
2017/02/09 NodeJs
Angular中ng-bind和ng-model的区别实例详解
2017/04/10 Javascript
JS实现HTML页面中动态显示当前时间完整示例
2018/07/30 Javascript
微信小程序实现展示评分结果功能
2019/02/15 Javascript
在Python的Django框架中显示对象子集的方法
2015/07/21 Python
python实现中文转换url编码的方法
2016/06/14 Python
python通过socket实现多个连接并实现ssh功能详解
2017/11/08 Python
Windows下的Jupyter Notebook 安装与自定义启动(图文详解)
2018/02/21 Python
Jupyter安装nbextensions,启动提示没有nbextensions库
2020/04/23 Python
Anaconda配置pytorch-gpu虚拟环境的图文教程
2020/04/16 Python
matplotlib 生成的图像中无法显示中文字符的解决方法
2020/06/10 Python
详解如何获取localStorage最大存储大小的方法
2020/05/21 HTML / CSS
美国顶级户外凉鞋品牌:Chacos
2017/03/27 全球购物
草莓网中国:StrawberryNet中国
2020/08/17 全球购物
用C#语言写出在本地创建一个UDP接收端口的具体过程
2016/02/22 面试题
环境科学专业个人求职的自我评价
2013/11/28 职场文书
网络书店创业计划书
2014/02/07 职场文书
2014年母亲节寄语
2014/05/07 职场文书
高中生第一学年自我鉴定
2014/09/12 职场文书
机关作风建设自查报告及整改措施
2014/10/21 职场文书
个人先进材料范文
2014/12/30 职场文书
详解使用 CSS prefers-* 规范提升网站的可访问性与健壮性
2021/05/25 HTML / CSS
Tomcat starup.bat 脚本实现开机自启动
2022/04/20 Servers