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操作mysql中文显示乱码的解决方法
Oct 11 Python
开源Web应用框架Django图文教程
Mar 09 Python
Windows和Linux下Python输出彩色文字的方法教程
May 02 Python
Python初学时购物车程序练习实例(推荐)
Aug 08 Python
python实战之实现excel读取、统计、写入的示例讲解
May 02 Python
python连接mongodb密码认证实例
Oct 16 Python
Python os.rename() 重命名目录和文件的示例
Oct 25 Python
Django保护敏感信息的方法示例
May 09 Python
使用opencv将视频帧转成图片输出
Dec 10 Python
解决json中ensure_ascii=False的问题
Apr 03 Python
python - timeit 时间模块
Apr 06 Python
使用python将HTML转换为PDF pdfkit包(wkhtmltopdf) 的使用方法
Apr 21 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 If Else(elsefi) 语句
2013/04/07 PHP
解析coreseek for sphinx的使用
2013/06/21 PHP
PHP图像处理类库及演示分享
2015/05/17 PHP
Thinkphp模板标签if和eq的区别和比较实例分析
2015/07/01 PHP
js 页面传参数时 参数值含特殊字符的问题
2009/12/13 Javascript
Jquery easyui 下loaing效果示例代码
2013/08/12 Javascript
使用forever管理nodejs应用教程
2014/06/03 NodeJs
node.js操作mongodb学习小结
2015/04/25 Javascript
jquery遍历标签中自定义的属性方法
2016/09/17 Javascript
Flask中获取小程序Request数据的两种方法
2017/05/12 Javascript
jqgrid实现简单的单行编辑功能
2017/09/30 Javascript
angularjs实现分页和搜索功能
2018/01/03 Javascript
微信小程序之分享页面如何返回首页的示例
2018/03/28 Javascript
详解在React项目中安装并使用Less(用法总结)
2019/03/18 Javascript
JS删除String里某个字符的方法
2021/01/06 Javascript
es6中class类静态方法,静态属性,实例属性,实例方法的理解与应用分析
2020/02/15 Javascript
Vue项目中使用flow做类型检测的方法
2020/03/18 Javascript
[01:03:00]DOTA2上海特级锦标赛A组败者赛 EHOME VS CDEC第一局
2016/02/25 DOTA
[44:01]2018DOTA2亚洲邀请赛3月30日 小组赛B组 EG VS paiN
2018/03/31 DOTA
[01:07:21]NAVI vs VG Supermajor 败者组 BO3 第二场 6.5
2018/06/06 DOTA
python复制文件的方法实例详解
2015/05/22 Python
python机器学习理论与实战(五)支持向量机
2018/01/19 Python
python实现树形打印目录结构
2018/03/29 Python
详谈python中冒号与逗号的区别
2018/04/18 Python
Python八大常见排序算法定义、实现及时间消耗效率分析
2018/04/27 Python
Python实现多级目录压缩与解压文件的方法
2018/09/01 Python
python实现生成Word、docx文件的方法分析
2019/08/30 Python
pytorch torch.expand和torch.repeat的区别详解
2019/11/05 Python
Python+kivy BoxLayout布局示例代码详解
2020/12/28 Python
学徒工职责
2014/03/06 职场文书
鸿星尔克广告词
2014/03/21 职场文书
助人为乐好少年事迹材料
2014/08/18 职场文书
销售竞赛活动方案
2014/08/23 职场文书
2014年实习期工作总结
2014/11/27 职场文书
上班迟到检讨书范文
2015/05/06 职场文书
上手简单,功能强大的Python爬虫框架——feapder
2021/04/27 Python