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使用xlrd读取Excel格式文件的方法
Mar 10 Python
Python实现的Google IP 可用性检测脚本
Apr 23 Python
Python base64编码解码实例
Jun 21 Python
python+selenium实现登录账户后自动点击的示例
Dec 22 Python
python微信公众号开发简单流程
Mar 23 Python
利用Python读取txt文档的方法讲解
Jun 23 Python
python实现任意位置文件分割的实例
Dec 14 Python
python字符串切割:str.split()与re.split()的对比分析
Jul 16 Python
Python实现一个数组除以一个数的例子
Jul 20 Python
50行Python代码获取高考志愿信息的实现方法
Jul 23 Python
Python转换itertools.chain对象为数组的方法
Feb 07 Python
Python通过正则库爬取淘宝商品信息代码实例
Mar 02 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
web方式ftp
2006/10/09 PHP
php中使用addslashes函数报错问题的解决方法
2013/02/06 PHP
php rmdir使用递归函数删除非空目录实例详解
2016/10/20 PHP
Laravel5.5 实现后台管理登录的方法(自定义用户表登录)
2019/09/30 PHP
Prototype Function对象 学习
2009/07/12 Javascript
最好用的省市二级联动 原生js实现你值得拥有
2013/09/22 Javascript
JS正则表达式大全(整理详细且实用)
2013/11/14 Javascript
js判断是否按下了Shift键的方法
2015/01/27 Javascript
JavaScript获取页面中第一个锚定文本的方法
2015/04/03 Javascript
jQuery常用且重要方法汇总
2015/07/13 Javascript
深入理解React中es6创建组件this的方法
2016/08/29 Javascript
Angular和百度地图的结合实例代码
2016/10/19 Javascript
nodeJS删除文件方法示例
2016/12/25 NodeJs
JS简单实现数组去重的方法示例
2017/03/27 Javascript
浅谈ECMAScript6新特性之let、const
2017/08/02 Javascript
JS中的BOM应用
2018/02/02 Javascript
js获取html页面代码中图片地址的实现代码
2018/03/05 Javascript
微信小程序定义和调用全局变量globalData的实现
2019/11/01 Javascript
微信小程序图片自适应实现解析
2020/01/21 Javascript
微信小程序入门之指南针
2020/10/22 Javascript
vantUI 获得piker选中值的自定义ID操作
2020/11/04 Javascript
[48:37]EG vs OG 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/18 DOTA
使用Python读取大文件的方法
2018/02/11 Python
python微信跳一跳系列之棋子定位颜色识别
2018/02/26 Python
Windows系统Python直接调用C++ DLL的方法
2019/08/01 Python
详解Django3中直接添加Websockets方式
2020/02/12 Python
Python线程协作threading.Condition实现过程解析
2020/03/12 Python
Get The Label中文官网:英国运动时尚购物平台
2017/04/19 全球购物
优秀求职自荐信怎样写
2013/12/18 职场文书
青年创业培训欢迎词
2014/01/08 职场文书
普通大学毕业生自荐信范文
2014/02/23 职场文书
公司采购主管岗位职责
2014/06/17 职场文书
公务员年度考核评语
2014/12/31 职场文书
介绍信怎么写
2015/05/05 职场文书
禁毒主题班会教案
2015/08/14 职场文书
利用Redis实现点赞功能的示例代码
2022/06/28 Redis