Python多线程中阻塞(join)与锁(Lock)使用误区解析


Posted in Python onApril 27, 2018

关于阻塞主线程

join的错误用法

Thread.join() 作用为阻塞主线程,即在子线程未返回的时候,主线程等待其返回然后再继续执行.

join不能与start在循环里连用
以下为错误代码,代码创建了5个线程,然后用一个循环激活线程,激活之后令其阻塞主线程.

threads = [Thread() for i in range(5)]
for thread in threads:
 thread.start()
 thread.join()

执行过程:

1. 第一次循环中,主线程通过start函数激活线程1,线程1进行计算.
2. 由于start函数不阻塞主线程,在线程1进行运算的同时,主线程向下执行join函数.
3. 执行join之后,主线程被线程1阻塞,在线程1返回结果之前,主线程无法执行下一轮循环.
4. 线程1计算完成之后,解除对主线程的阻塞.
5. 主线程进入下一轮循环,激活线程2并被其阻塞…

如此往复,可以看出,本来应该并发的五个线程,在这里变成了顺序队列,效率和单线程无异.

join的正确用法

使用两个循环分别处理startjoin函数.即可实现并发.

threads = [Thread() for i in range(5)]
for thread in threads:
 thread.start()
for thread in threads:
 thread.join()

time.sleep代替join进行调试

之前在一些项目里看到过这样的代码,使用time.sleep代替join手动阻塞主线程.
在所有子线程返回之前,主线程陷入无线循环而不能退出.

for thread in threads:
 thread.start()
while 1:
 if thread_num == 0:
 break
 time.sleep(0.01)

关于线程锁(threading.Lock)

单核CPU+PIL是否还需要锁?

非原子操作 count = count + 1 理论上是线程不安全的.
使用3个线程同时执行上述操作改变全局变量count的值,并查看程序执行结果.
如果结果正确,则表示未出现线程冲突.

使用以下代码测试

# -*- coding: utf-8 -*-

import threading
import time
count = 0

class Counter(threading.Thread):
 def __init__(self, name):
 self.thread_name = name
 super(Counter, self).__init__(name=name)

 def run(self):
 global count
 for i in xrange(100000):
  count = count + 1


counters = [Counter('thread:%s' % i) for i in range(5)]
for counter in counters:
 counter.start()

time.sleep(5)
print 'count=%s' % count

运行结果:

count=275552

事实上每次运行结果都不相同且不正确,这证明单核CPU+PIL仍无法保证线程安全,需要加锁.

加锁后的正确代码:

# -*- coding: utf-8 -*-

import threading
import time

count = 0
lock = threading.Lock()


class Counter(threading.Thread):
 def __init__(self, name):
 self.thread_name = name
 self.lock = threading.Lock()
 super(Counter, self).__init__(name=name)

 def run(self):
 global count
 global lock
 for i in xrange(100000):
  lock.acquire()
  count = count + 1
  lock.release()


counters = [Counter('thread:%s' % i) for i in range(5)]

for counter in counters:
 counter.start()

time.sleep(5)
print 'count=%s' % count

结果:

count=500000

注意锁的全局性

这是一个简单的Python语法问题,但在逻辑复杂时有可能被忽略.
要保证锁对于多个子线程来说是共用的,即不要在Thread的子类内部创建锁.

以下为错误代码

# -*- coding: utf-8 -*-

import threading
import time

count = 0
# lock = threading.Lock() # 正确的声明位置

class Counter(threading.Thread):
 def __init__(self, name):
 self.thread_name = name
 self.lock = threading.Lock() # 错误的声明位置
 super(Counter, self).__init__(name=name)

 def run(self):
 global count
 for i in xrange(100000):
  self.lock.acquire()
  count = count + 1
  self.lock.release()


counters = [Counter('thread:%s' % i) for i in range(5)]

for counter in counters:
 print counter.thread_name
 counter.start()

time.sleep(5)
print 'count=%s' % count

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python3.x和Python2.x的区别介绍
Feb 12 Python
Python中read()、readline()和readlines()三者间的区别和用法
Jul 30 Python
Python八大常见排序算法定义、实现及时间消耗效率分析
Apr 27 Python
python3.5 email实现发送邮件功能
May 22 Python
python 读取.csv文件数据到数组(矩阵)的实例讲解
Jun 14 Python
python绘制直线的方法
Jun 30 Python
pytz格式化北京时间多出6分钟问题的解决方法
Jun 21 Python
opencv python 图片读取与显示图片窗口未响应问题的解决
Apr 24 Python
python interpolate插值实例
Jul 06 Python
jupyter notebook 写代码自动补全的实现
Nov 02 Python
Python获取指定网段正在使用的IP
Dec 14 Python
PyCharm 解决找不到新打开项目的窗口问题
Jan 15 Python
python队列queue模块详解
Apr 27 #Python
浅谈tensorflow1.0 池化层(pooling)和全连接层(dense)
Apr 27 #Python
python线程中同步锁详解
Apr 27 #Python
python数字图像处理之高级形态学处理
Apr 27 #Python
python线程池threadpool实现篇
Apr 27 #Python
python数字图像处理之骨架提取与分水岭算法
Apr 27 #Python
python多线程之事件Event的使用详解
Apr 27 #Python
You might like
人族 Terran 魔法与科技
2020/03/14 星际争霸
PHP 函数语法介绍一
2009/06/14 PHP
PHP实现AES256加密算法实例
2014/09/22 PHP
php出现web系统多域名登录失败的解决方法
2014/09/30 PHP
php+ajax实现无刷新文件上传功能(ajaxuploadfile)
2018/02/11 PHP
JavaScript 轻松搞定快捷留言功能 只需一行代码
2010/04/01 Javascript
使用jQuery的将桌面应用程序引入浏览器
2010/11/19 Javascript
js模拟滚动条(横向竖向)
2013/02/22 Javascript
JQGrid的用法解析(列编辑,添加行,删除行)
2013/11/08 Javascript
JavaScript中获取鼠标位置相关属性总结
2014/10/11 Javascript
jQuery模拟原生态App上拉刷新下拉加载更多页面及原理
2015/08/10 Javascript
JavaScript实现图片轮播组件代码示例
2016/11/22 Javascript
JavaScript获取键盘按键的键码(参照表)
2017/01/10 Javascript
js中Object.defineProperty()方法的不详解
2018/07/09 Javascript
详解js删除数组中的指定元素
2018/10/31 Javascript
jQuery - AJAX load() 实例用法详解
2019/08/27 jQuery
vue实现拖拽效果
2019/12/23 Javascript
微信小程序中的上拉、下拉菜单功能
2020/03/13 Javascript
js对象属性名驼峰式转下划线的实例代码
2020/09/17 Javascript
python 从远程服务器下载日志文件的程序
2013/02/10 Python
python写一个md5解密器示例
2018/02/23 Python
通过Py2exe将自己的python程序打包成.exe/.app的方法
2018/05/26 Python
离线状态下在jupyter notebook中使用plotly实例
2020/04/24 Python
Python实现手绘图效果实例分享
2020/07/22 Python
Pytorch 中的optimizer使用说明
2021/03/03 Python
Html5如何唤起百度地图App的方法
2019/01/27 HTML / CSS
毕业生个人求职的自我评价
2013/10/28 职场文书
教师自我鉴定范文
2013/11/10 职场文书
《自选商场》教学反思
2014/02/14 职场文书
党的群众路线教育实践活动个人整改措施范文
2014/11/04 职场文书
住房公积金贷款工资证明
2015/06/12 职场文书
欠款证明
2015/06/24 职场文书
如何利用STAR法则制作留学文书?
2019/08/26 职场文书
初中运动会闭幕词范本3篇
2019/12/09 职场文书
python 实现mysql自动增删分区的方法
2021/04/01 Python
Golang并发操作中常见的读写锁详析
2021/08/30 Golang