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 django集成cas验证系统
Jul 14 Python
python编写暴力破解FTP密码小工具
Nov 19 Python
python统计日志ip访问数的方法
Jul 06 Python
使用Django的模版来配合字符串翻译工作
Jul 27 Python
python 出现SyntaxError: non-keyword arg after keyword arg错误解决办法
Feb 14 Python
Python3.6中Twisted模块安装的问题与解决
Apr 15 Python
Python考拉兹猜想输出序列代码实践
Jul 05 Python
Python实现简单的列表冒泡排序和反转列表操作示例
Jul 10 Python
python opencv将图片转为灰度图的方法示例
Jul 31 Python
SpringBoot实现登录注册常见问题解决方案
Mar 04 Python
什么是python的自省
Jun 21 Python
pandas DataFrame.shift()函数的具体使用
May 24 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笔记之:AOP的应用
2013/04/24 PHP
Php-Redis安装测试笔记
2015/03/05 PHP
微信公众平台开发之天气预报功能
2015/08/31 PHP
PHP+Ajax实现的无刷新分页功能详解【附demo源码下载】
2017/07/03 PHP
Laravel模型间关系设置分表的方法示例
2018/04/21 PHP
PHP生成指定范围内的N个不重复的随机数
2019/03/18 PHP
常见的5个PHP编码小陋习以及优化实例讲解
2021/02/27 PHP
javascript FormatNumber函数实现方法
2008/12/30 Javascript
实用的Jquery选项卡TAB示例代码
2013/08/28 Javascript
下拉列表select 由左边框移动到右边示例
2013/12/04 Javascript
深入理解JavaScript系列(46):代码复用模式(推荐篇)详解
2015/03/04 Javascript
js如何改变文章的字体大小
2016/01/08 Javascript
jQuery.Callbacks()回调函数队列用法详解
2016/06/14 Javascript
用AngularJS的指令实现tabs切换效果
2016/08/31 Javascript
JavaScript实现图片轮播组件代码示例
2016/11/22 Javascript
bootstrap laydate日期组件使用详解
2017/01/04 Javascript
Angular.js组件之input mask对input输入进行格式化详解
2017/07/10 Javascript
JavaScript设计模式之单例模式原理与用法实例分析
2018/07/26 Javascript
js中arguments对象的深入理解
2019/05/14 Javascript
[01:51]DAC趣味视频-如何成为职业选手.mp4
2017/04/02 DOTA
Python中的pprint折腾记
2015/01/21 Python
python集合类型用法分析
2015/04/08 Python
Python使用redis pool的一种单例实现方式
2016/04/16 Python
浅谈终端直接执行py文件,不需要python命令
2017/01/23 Python
Linux-ubuntu16.04 Python3.5配置OpenCV3.2的方法
2018/04/02 Python
利用python-docx模块写批量生日邀请函
2019/08/26 Python
解决python有时候import不了当前的包问题
2019/08/28 Python
Python查找不限层级Json数据中某个key或者value的路径方式
2020/02/27 Python
Django获取model中的字段名和字段的verbose_name方式
2020/05/19 Python
Python hashlib和hmac模块使用方法解析
2020/12/08 Python
html5 touch事件实现页面上下滑动效果【附代码】
2016/03/10 HTML / CSS
应届生保险求职信
2013/11/11 职场文书
《画家乡》教学反思
2014/04/22 职场文书
简历自荐信范文
2015/03/09 职场文书
Vue实现下拉加载更多
2021/05/09 Vue.js
python中的3种定义类方法
2021/11/27 Python