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重试装饰器示例
Feb 11 Python
用Python制作在地图上模拟瘟疫扩散的Gif图
Mar 31 Python
Pycharm 操作Django Model的简单运用方法
May 23 Python
在IPython中进行Python程序执行时间的测量方法
Nov 01 Python
python抖音表白程序源代码
Apr 07 Python
详解Python sys.argv使用方法
May 10 Python
Flask框架学习笔记之消息提示与异常处理操作详解
Aug 15 Python
Python Django搭建网站流程图解
Jun 13 Python
PyTorch的torch.cat用法
Jun 28 Python
在keras中对单一输入图像进行预测并返回预测结果操作
Jul 09 Python
Python数据可视化实现漏斗图过程图解
Jul 20 Python
python实现控制台输出颜色
Mar 02 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页码形式分页函数支持静态化地址及ajax分页
2014/03/28 PHP
PHP图片等比例缩放生成缩略图函数分享
2014/06/10 PHP
Yii2前后台分离及migrate使用(七)
2016/05/04 PHP
PHP抓取远程图片(含不带后缀的)教程详解
2016/10/21 PHP
jquery实现当滑动到一定位置时固定效果
2014/06/17 Javascript
Javascript获取当前时间函数和时间操作小结
2014/10/01 Javascript
生成二维码方法汇总
2014/12/26 Javascript
3种js实现string的substring方法
2015/11/09 Javascript
Adapter适配器模式在JavaScript设计模式编程中的运用分析
2016/05/18 Javascript
Bootstrop实现多级下拉菜单功能
2016/11/24 Javascript
JavaScript实现经典排序算法之选择排序
2016/12/28 Javascript
JavaScript基于replace+正则实现ES6的字符串模版功能
2017/04/25 Javascript
jquery如何实现点击空白处隐藏元素
2017/12/05 jQuery
原生JS实现$.param() 函数的方法
2018/08/10 Javascript
Vue动态修改网页标题的方法及遇到问题
2019/06/09 Javascript
Python中random模块生成随机数详解
2016/03/10 Python
Python3使用requests包抓取并保存网页源码的方法
2016/03/15 Python
python基础练习之几个简单的游戏
2017/11/10 Python
numpy.transpose对三维数组的转置方法
2018/04/17 Python
python f-string式格式化听语音流程讲解
2019/06/18 Python
一篇文章了解Python中常见的序列化操作
2019/06/20 Python
Python企业编码生成系统总体系统设计概述
2019/07/26 Python
pycharm激活码快速激活及使用步骤
2020/03/12 Python
keras slice layer 层实现方式
2020/06/11 Python
您在慕尼黑的跑步商店:Lauf-bar
2019/10/11 全球购物
汽车运用工程系毕业生自荐信
2013/12/27 职场文书
网上签名寄语活动留言
2014/01/18 职场文书
教师评语大全
2014/04/28 职场文书
我爱幼儿园演讲稿
2014/09/11 职场文书
2015年大学班长个人工作总结
2015/04/24 职场文书
高中开学感言
2015/08/01 职场文书
三好学生竞选稿范文
2019/08/21 职场文书
分析JVM源码之Thread.interrupt系统级别线程打断
2021/06/29 Java/Android
Python实现视频自动打码的示例代码
2022/04/08 Python
Python selenium绕过webdriver监测执行javascript
2022/04/12 Python
详解CSS3浏览器兼容
2022/12/24 HTML / CSS