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实现2048小游戏
Mar 30 Python
Python文本相似性计算之编辑距离详解
Nov 28 Python
Python决策树和随机森林算法实例详解
Jan 30 Python
DataFrame中去除指定列为空的行方法
Apr 08 Python
Python查找第n个子串的技巧分享
Jun 27 Python
python+pandas+时间、日期以及时间序列处理方法
Jul 10 Python
python os.path模块常用方法实例详解
Sep 16 Python
python程序封装为win32服务的方法
Mar 07 Python
Python基于百度云文字识别API
Dec 13 Python
python之当你发现QTimer不能用时的解决方法
Jun 21 Python
PyCharm2019安装教程及其使用(图文教程)
Sep 29 Python
使用 pytorch 创建神经网络拟合sin函数的实现
Feb 24 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与SQL注入攻击[二]
2007/04/17 PHP
php lcg_value与mt_rand生成0~1随机小数的效果对比分析
2017/04/05 PHP
php递归函数怎么用才有效
2018/02/24 PHP
JavaScript实现动态增加文件域表单
2009/02/12 Javascript
js apply/call/caller/callee/bind使用方法与区别分析
2009/10/28 Javascript
jQuery实现个性翻牌效果导航菜单的方法
2015/03/09 Javascript
JavaScript正则表达式之multiline属性的应用
2015/06/16 Javascript
谈谈我对JavaScript原型和闭包系列理解(随手笔记8)
2015/12/24 Javascript
JavaScript编写点击查看大图的页面半透明遮罩层效果实例
2016/05/09 Javascript
javascript实现标签切换代码示例
2016/05/22 Javascript
基于JavaScript实现购物网站商品放大镜效果
2016/09/06 Javascript
使用vue制作FullPage页面滚动效果
2017/08/21 Javascript
使用ionic(选项卡栏tab) icon(图标) ionic上拉菜单(ActionSheet) 实现通讯录界面切换实例代码
2017/10/20 Javascript
js使用xml数据载体实现城市省份二级联动效果
2017/11/08 Javascript
使用Vue构建可重用的分页组件
2018/03/26 Javascript
jquery实现Ajax请求的几种常见方式总结
2019/05/28 jQuery
jQuery实现图片切换效果
2020/10/19 jQuery
python利用hook技术破解https的实例代码
2013/03/25 Python
浅谈对yield的初步理解
2017/05/29 Python
Django添加KindEditor富文本编辑器的使用
2018/10/24 Python
详解python3安装pillow后报错没有pillow模块以及没有PIL模块问题解决
2019/04/17 Python
Python编写带选项的命令行程序方法
2019/08/13 Python
python递归下载文件夹下所有文件
2019/08/31 Python
解析Python3中的Import
2019/10/13 Python
Python os模块常用方法和属性总结
2020/02/20 Python
python查找特定名称文件并按序号、文件名分行打印输出的方法
2020/04/24 Python
HTML5实现直播间评论滚动效果的代码
2020/05/27 HTML / CSS
美国受欢迎的眼影品牌:BH Cosmetics
2016/10/25 全球购物
英格兰橄榄球商店:England Rugby Store
2016/12/17 全球购物
苏格兰在线威士忌商店:The Whisky Barrel
2019/05/07 全球购物
香港零食网购:上仓胃子
2020/06/08 全球购物
学生发电厂实习自我鉴定
2013/09/22 职场文书
煤矿班组长岗位职责
2013/12/29 职场文书
党员批评与自我批评材料
2014/10/14 职场文书
大学生学生会工作总结2015
2015/05/26 职场文书
Java 深入探究讲解简单工厂模式
2022/04/07 Java/Android