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函数的参数的默认值所引发的问题的原因
Mar 30 Python
在Django的视图中使用数据库查询的方法
Jul 16 Python
Python实现将文本生成二维码的方法示例
Jul 18 Python
python 函数传参之传值还是传引用的分析
Sep 07 Python
Python+tkinter使用80行代码实现一个计算器实例
Jan 16 Python
python3 kmp 字符串匹配的方法
Jul 07 Python
Sanic框架流式传输操作示例
Jul 18 Python
python re正则匹配网页中图片url地址的方法
Dec 20 Python
python将txt等文件中的数据读为numpy数组的方法
Dec 22 Python
python实现五子棋小游戏
Mar 25 Python
详解Django3中直接添加Websockets方式
Feb 12 Python
浅析pip安装第三方库及pycharm中导入第三方库的问题
Mar 10 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实现的下载css文件中的图片的代码
2010/02/08 PHP
windows7下安装php的php-ssh2扩展教程
2014/07/04 PHP
PHP函数实现分页含文本分页和数字分页
2014/10/23 PHP
PHP也能干大事之PHP中的编码解码详解
2015/04/20 PHP
css把超出的部分显示为省略号的方法兼容火狐
2008/07/23 Javascript
JS 实现BASE64_ENCODE和BASE64_DECODE(实例代码)
2013/11/13 Javascript
JS实现的生成随机数的4个函数分享
2015/02/11 Javascript
JS+CSS实现感应鼠标渐变显示DIV层的方法
2015/02/20 Javascript
headjs实现网站并行加载但顺序执行JS
2016/11/29 Javascript
jQuery使用eraser.js插件实现擦除、刮刮卡效果的方法【附eraser.js下载】
2017/04/28 jQuery
vue实现手机号码抽奖上下滚动动画示例
2017/10/18 Javascript
vue.js 图片上传并预览及图片更换功能的实现代码
2018/08/27 Javascript
JS中验证整数和小数的正则表达式
2018/10/08 Javascript
手把手教你如何使用nodejs编写cli命令行
2018/11/05 NodeJs
微信小程序仿知乎实现评论留言功能
2018/11/28 Javascript
JS/HTML5游戏常用算法之碰撞检测 像素检测算法实例详解
2018/12/12 Javascript
[10:53]2018DOTA2国际邀请赛寻真——EG
2018/08/11 DOTA
Python使用Srapy框架爬虫模拟登陆并抓取知乎内容
2016/07/02 Python
实现python版本的按任意键继续/退出
2016/09/26 Python
Tensorflow的可视化工具Tensorboard的初步使用详解
2018/02/11 Python
python解决pandas处理缺失值为空字符串的问题
2018/04/08 Python
python爬虫 爬取58同城上所有城市的租房信息详解
2019/07/30 Python
Python实现RGB与HSI颜色空间的互换方式
2019/11/27 Python
CSS3弹性伸缩布局之box布局
2016/07/12 HTML / CSS
css3绘制百度的小度熊
2018/10/29 HTML / CSS
使用css实现android系统的loading加载动画
2019/07/25 HTML / CSS
Draper James官网:知名演员瑞茜·威瑟斯彭所创品牌
2017/10/25 全球购物
美国本地交易和折扣网站:LocalFlavor.com
2017/10/26 全球购物
英国伦敦的睡衣品牌:Asceno
2019/10/06 全球购物
State Cashmere官网:半零售价可持续蒙古羊绒
2020/02/26 全球购物
《都江堰》教学反思
2014/02/07 职场文书
《藤野先生》教学反思
2014/02/19 职场文书
某集团股份有限公司委托书样本
2014/09/24 职场文书
群众路线教育实践活动自我剖析思想汇报
2014/10/04 职场文书
MySQL 百万级数据的4种查询优化方式
2021/06/07 MySQL
MySQL去除重叠时间求时间差和的实现
2021/08/23 MySQL