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中数字以及算数运算符的相关使用
Oct 12 Python
Python实现嵌套列表去重方法示例
Dec 28 Python
python实现百万答题自动百度搜索答案
Jan 16 Python
pycharm运行和调试不显示结果的解决方法
Nov 30 Python
pyttsx3实现中文文字转语音的方法
Dec 24 Python
python flask安装和命令详解
Apr 02 Python
深入了解Django View(视图系统)
Jul 23 Python
django实现类似触发器的功能
Nov 15 Python
关于Flask项目无法使用公网IP访问的解决方式
Nov 19 Python
pytorch GAN生成对抗网络实例
Jan 10 Python
Keras 利用sklearn的ROC-AUC建立评价函数详解
Jun 15 Python
Django日志及中间件模块应用案例
Sep 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 源代码压缩小工具
2009/12/22 PHP
Codeigniter通过SimpleXML将xml转换成对象的方法
2015/03/19 PHP
PHP读取大文件的几种方法介绍
2016/10/27 PHP
PHP版微信小店接口开发实例
2016/11/12 PHP
Linux下快速搭建php开发环境
2017/03/13 PHP
JavaScript中实现块作用域的方法
2010/04/01 Javascript
js为数字添加逗号并格式化数字的代码
2013/08/23 Javascript
Jquery attr("checked") 返回checked或undefined 获取选中失效
2013/10/10 Javascript
初识SmartJS - AOP三剑客
2014/06/08 Javascript
javascript面向对象之定义成员方法实例分析
2015/01/13 Javascript
Highcharts使用简例及异步动态读取数据
2015/12/30 Javascript
jquery实现具有收缩功能的垂直导航菜单
2016/02/16 Javascript
Bootstrap模仿起筷首页效果
2016/05/09 Javascript
JavaScript中校验银行卡号的实现代码
2016/12/19 Javascript
微信小程序开发的四十个技术窍门总结(推荐)
2017/01/23 Javascript
Vue.js 2.0 移动端拍照压缩图片上传预览功能
2017/03/06 Javascript
AngularJS日程表案例详解
2017/08/15 Javascript
微信小程序倒计时功能实现代码
2017/11/09 Javascript
nodejs+mongodb aggregate级联查询操作示例
2018/03/17 NodeJs
LayUI动态设置checkbox不显示的解决方法
2019/09/02 Javascript
基于javascript canvas实现五子棋游戏
2020/07/08 Javascript
OpenLayer学习之自定义测量控件
2020/09/28 Javascript
理解Python中函数的参数
2015/04/27 Python
Python实现字典依据value排序
2016/02/24 Python
详解Python安装tesserocr遇到的各种问题及解决办法
2019/03/07 Python
Python + Requests + Unittest接口自动化测试实例分析
2019/12/12 Python
Python文本处理简单易懂方法解析
2019/12/19 Python
Vs Code中8个好用的python 扩展插件
2020/10/12 Python
Shopee菲律宾:在线购买和出售
2019/11/25 全球购物
个人求职信范文分享
2014/01/31 职场文书
中文专业学生自我评价范文
2014/02/06 职场文书
手机被没收检讨书
2014/02/22 职场文书
2014年公务员个人工作总结
2014/11/22 职场文书
辞职信格式范文
2015/05/13 职场文书
小学主题班会教案
2015/08/17 职场文书
搞笑婚礼主持词开场白
2015/11/24 职场文书