Python中多线程及程序锁浅析


Posted in Python onJanuary 21, 2015

Python中多线程使用到Threading模块。Threading模块中用到的主要的类是Thread,我们先来写一个简单的多线程代码:

# coding : uft-8

__author__ = 'Phtih0n'

import threading
class MyThread(threading.Thread):

    def __init__(self):

        threading.Thread.__init__(self)
    def run(self):

        global n

        print n

        n += 1
if "__main__" == __name__:

    n = 0

    ThreadList = []

    for i in range(0, 10):

        t = MyThread()

        ThreadList.append(t)

    for t in ThreadList:

        t.start()

    for t in ThreadList:

        t.join

最普通的一个多线程小例子。我一笔带过地讲一讲,我创建了一个继承Thread类的子类MyThread,作为我们的线程启动类。按照规定,重写Thread的run方法,我们的线程启动起来后会自动调用该方法。于是我首先创建了10个线程,并将其加入列表中。再使用一个for循环,开启每个线程。在使用一个for循环,调用join方法等待所有线程结束才退出主线程。

这段代码看似简单,但实际上隐藏着一个很大的问题,只是在这里没有体现出来。你真的以为我创建了10个线程,并按顺序调用了这10个线程,每个线程为n增加了1.实际上,有可能是A线程执行了n++,再C线程执行了n++,再B线程执行n++。

这里涉及到一个“锁”的问题,如果有多个线程同时操作一个对象,如果没有很好地保护该对象,会造成程序结果的不可预期(比如我们在每个线程的run方法中加入一个time.sleep(1),并同时输出线程名称,则我们会发现,输出会乱七八糟。因为可能我们的一个print语句只打印出一半的字符,这个线程就被暂停,执行另一个去了,所以我们看到的结果很乱),这种现象叫做“线程不安全”:

Python中多线程及程序锁浅析

于是,Threading模块为我们提供了一个类,Threading.Lock,锁。我们创建一个该类对象,在线程函数执行前,“抢占”该锁,执行完成后,“释放”该锁,则我们确保了每次只有一个线程占有该锁。这时候对一个公共的对象进行操作,则不会发生线程不安全的现象了。

于是,我们把代码更改如下:

# coding : uft-8

__author__ = 'Phtih0n'

import threading, time
class MyThread(threading.Thread):

    def __init__(self):

        threading.Thread.__init__(self)
    def run(self):

        global n, lock

        time.sleep(1)

        if lock.acquire():

            print n , self.name

            n += 1

            lock.release()
if "__main__" == __name__:

    n = 1

    ThreadList = []

    lock = threading.Lock()

    for i in range(1, 200):

        t = MyThread()

        ThreadList.append(t)

    for t in ThreadList:

        t.start()

    for t in ThreadList:

        t.join()

最后执行结果:

Python中多线程及程序锁浅析

我们看到,我们先建立了一个threading.Lock类对象lock,在run方法里,我们使用lock.acquire()获得了这个锁。此时,其他的线程就无法再获得该锁了,他们就会阻塞在“if lock.acquire()”这里,直到锁被另一个线程释放:lock.release()。

所以,if语句中的内容就是一块完整的代码,不会再存在执行了一半就暂停去执行别的线程的情况。所以最后结果是整齐的。

就如同在java中,我们使用synchronized关键字修饰一个方法,目的一样,让某段代码被一个线程执行时,不会打断跳到另一个线程中。

这是多线程占用一个公共对象时候的情况。如果多个线程要调用多个现象,而A线程调用A锁占用了A对象,B线程调用了B锁占用了B对象,A线程不能调用B对象,B线程不能调用A对象,于是一直等待。这就造成了线程“死锁”。

Threading模块中,也有一个类,RLock,称之为可重入锁。该锁对象内部维护着一个Lock和一个counter对象。counter对象记录了acquire的次数,使得资源可以被多次require。最后,当所有RLock被release后,其他线程才能获取资源。在同一个线程中,RLock.acquire可以被多次调用,利用该特性,可以解决部分死锁问题。

死锁问题很复杂,多年来人们想出了很多算法来解决它。我就不再多说,具体还是要大家参阅帮助文档。

Python 相关文章推荐
python抓取京东商城手机列表url实例代码
Dec 18 Python
Python字符串转换成浮点数函数分享
Jul 24 Python
Python字符串拼接的几种方法整理
Aug 02 Python
解决python大批量读写.doc文件的问题
May 08 Python
《与孩子一起学编程》python自测题
May 27 Python
用python实现k近邻算法的示例代码
Sep 06 Python
Opencv+Python实现图像运动模糊和高斯模糊的示例
Apr 11 Python
python远程邮件控制电脑升级版
May 23 Python
centos 安装Python3 及对应的pip教程详解
Jun 28 Python
python 扩展print打印文件路径和当前时间信息的实例代码
Oct 11 Python
解决jupyter notebook import error但是命令提示符import正常的问题
Apr 15 Python
python logging.info在终端没输出的解决
May 12 Python
Python实现的多线程端口扫描工具分享
Jan 21 #Python
Python中的pprint折腾记
Jan 21 #Python
通过C++学习Python
Jan 20 #Python
python入门之语句(if语句、while语句、for语句)
Jan 19 #Python
Python实现删除Android工程中的冗余字符串
Jan 19 #Python
Python中字典和JSON互转操作实例
Jan 19 #Python
Python中的字典遍历备忘
Jan 17 #Python
You might like
屏蔽PHP默认设置中的Notice警告的方法
2016/05/20 PHP
thinkPHP中验证码的简单实现方法
2016/12/05 PHP
PHP实现的简单留言板功能示例【基于thinkPHP框架】
2018/12/07 PHP
PHP去除空数组且数组键名重置的讲解
2019/02/28 PHP
php面向对象程序设计中self与static的区别分析
2019/05/21 PHP
仿服务器端脚本方式的JS模板实现方法
2007/04/27 Javascript
初学JavaScript_03(ExtJs Grid的简单使用)
2008/10/02 Javascript
javascript 学习笔记(onchange等)
2010/11/14 Javascript
通过上下左右键和回车键切换光标实现代码
2013/03/08 Javascript
简单几行JS Code实现IE邮件转发新浪微博
2013/07/03 Javascript
用JavaScript实现一个代码简洁、逻辑不复杂的多级树
2014/05/23 Javascript
Javascript基础教程之关键字和保留字汇总
2015/01/18 Javascript
Node.js中的流(Stream)介绍
2015/03/30 Javascript
JavaScript中的setMilliseconds()方法使用详解
2015/06/11 Javascript
jquery分析文本里url或邮件地址为真实链接的方法
2015/06/20 Javascript
使用nodejs+express实现简单的文件上传功能
2017/12/27 NodeJs
基于vue v-for 多层循环嵌套获取行数的方法
2018/09/26 Javascript
使用puppeteer爬取网站并抓出404无效链接
2018/12/20 Javascript
如何在Vue.JS中使用图标组件
2020/08/04 Javascript
[02:03]DOTA2亚洲邀请赛 HGT战队出场宣传片
2015/02/07 DOTA
Python时间戳与时间字符串互相转换实例代码
2013/11/28 Python
Python爬虫框架Scrapy实战之批量抓取招聘信息
2015/08/07 Python
python实现学生信息管理系统
2020/04/05 Python
浅谈keras中自定义二分类任务评价指标metrics的方法以及代码
2020/06/11 Python
浅析Python 抽象工厂模式的优缺点
2020/07/13 Python
python中判断文件结束符的具体方法
2020/08/04 Python
5分钟快速掌握Python定时任务框架的实现
2021/01/26 Python
CSS3实例分享--超炫checkbox复选框和radio单选框
2014/09/01 HTML / CSS
html5 Canvas画图教程(5)—canvas里画曲线之arc方法
2013/01/09 HTML / CSS
Raleigh兰令自行车美国官网:英国凤头牌自行车
2018/01/08 全球购物
英语商务邀请函范文
2014/01/16 职场文书
幼师求职自荐信范文
2014/01/26 职场文书
小学校园广播稿(3篇)
2014/09/19 职场文书
先进教育工作者事迹材料
2014/12/23 职场文书
入党转正申请报告
2015/05/15 职场文书
python 模块重载的五种方法
2021/04/24 Python