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 相关文章推荐
Python实现生成简单的Makefile文件代码示例
Mar 10 Python
python使用post提交数据到远程url的方法
Apr 29 Python
python数据结构之图的实现方法
Jul 08 Python
Python下的常用下载安装工具pip的安装方法
Nov 13 Python
详解Python if-elif-else知识点
Jun 11 Python
Python实现的字典排序操作示例【按键名key与键值value排序】
Dec 21 Python
关于tensorflow的几种参数初始化方法小结
Jan 04 Python
解决Python图形界面中设置尺寸的问题
Mar 05 Python
使用Keras 实现查看model weights .h5 文件的内容
Jun 09 Python
编写python代码实现简单抽奖器
Oct 20 Python
Python性能测试工具Locust安装及使用
Dec 01 Python
Pytorch中使用ImageFolder读取数据集时忽略特定文件
Mar 23 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
PHP 中的面向对象编程:通向大型 PHP 工程的办法
2006/12/03 PHP
ThinkPHP多表联合查询的常用方法
2020/03/24 PHP
PHP创建PowerPoint2007文档的方法
2015/12/10 PHP
jquery实现网页查找功能示例分享
2014/02/12 Javascript
jQuery插件slick实现响应式移动端幻灯片图片切换特效
2015/04/12 Javascript
详解JavaScript中的表单验证
2015/06/16 Javascript
提高jQuery性能优化的技巧
2015/08/03 Javascript
AngularJS Ajax详解及示例代码
2016/08/17 Javascript
Node.js使用NodeMailer发送邮件实例代码
2017/03/06 Javascript
浅谈React中组件间抽象
2018/01/27 Javascript
React组件中的this的具体使用
2018/02/28 Javascript
js判断输入框不能为空格或null值的实现方法
2018/03/02 Javascript
AngularJS中的作用域实例分析
2018/05/16 Javascript
微信小程序mpvue点击按钮获取button值的方法
2019/05/29 Javascript
javascript解析json格式的数据方法详解
2020/08/07 Javascript
使用vant的地域控件追加全部选项
2020/11/03 Javascript
[02:04]2020年夜魇暗潮预告片
2020/10/30 DOTA
centos6.4下python3.6.1安装教程
2017/07/21 Python
python数据结构之列表和元组的详解
2017/09/23 Python
详解Python 正则表达式模块
2018/11/05 Python
基于python实现把图片转换成素描
2019/11/13 Python
Python-opencv 双线性插值实例
2020/01/17 Python
如何完美的建立一个python项目
2020/10/09 Python
AmazeUI 等分网格的实现示例
2020/08/25 HTML / CSS
高街生活方式全球在线商店:AZBRO
2017/08/26 全球购物
美国艺术和工艺品商店:Hobby Lobby
2020/12/09 全球购物
会计电算化专业毕业生自荐信
2013/12/20 职场文书
宝宝周岁宴答谢词
2014/01/26 职场文书
给校长的建议书400字
2014/05/15 职场文书
农村文化活动总结
2014/08/28 职场文书
2014预防青少年违法犯罪工作总结
2014/12/10 职场文书
人事文员岗位职责
2015/02/04 职场文书
办公室管理规章制度
2015/08/04 职场文书
班主任远程培训研修日志
2015/11/13 职场文书
提取视频中的音频 Python只需要三行代码!
2021/05/10 Python
python开发的自动化运维工具ansible详解
2021/08/07 Python