Python中多线程的阻塞问题
在使用Queue模块+多线程模拟生产者+消费者问题时,遇到了一个小问题,现在记录下来。供可能会遇到类似问题的初学者们参考。
该问题的完整参考代码如下。主要实现了以下的功能:在一个线程中,开启生产者模式,生成出来的object会put进一个Queue对象queue中。除此以外,在n个线程中(本代码中n为5,nfuncs = 5),开启消费者模式,每一个消费者线程会在一个while循环中不断地从queue中消耗一个object(使用get方法),直到生产者生产出的object被全部消耗(本代码中设为100个object)。
from random import randint
from time import sleep
from Queue import Queue
from threading import Thread,Lock,currentThread
lock = Lock()
def writes(queue):
print "producing object for Q...",
queue.put('xxx', 1)
print "size now", queue.qsize()
def readQ(queue):
val = queue.get(1)
print "consumed object from Q... size now", \
queue.qsize()
print currentThread().name
def writer(queue, loops):
for i in range(loops):
lock.acquire()
writes(queue)
lock.release()
sleep(0.1)
def read(queue):
while queue.qsize() >0 :
sleep(randint(2, 4))
lock.acquire()
readQ(queue)
lock.release()
funcs = [writer, read]
nfuncs = range(5)
def main():
nloops1 = 100
q = Queue(1024)
thread = []
t = Thread(target = writer, args = (q, nloops1))
thread.append(t)
for i in nfuncs:
t = Thread(target = read, args = (q,))
thread.append(t)
for i in range(len(thread)):
thread[i].start()
for i in range(len(thread)):
thread[i].join()
print "All Done"
if __name__ == '__main__':
main()
为了防止生产速度跟不上消费的速度,生产线程中每次生产仅间隔0.1秒,且在消费线程中每次消费之前,随机sleep 2~3秒。
在运行之后,生产的object数量达到100(实际不会print 100号object的生成,因为在生产的过程中已经开始消费),然后多个线程开始消费。然而在把object数量消费至0以后,线程们并不会结束,既“print “”All done“””语句一直没有被执行。
思考以后,得出了三种解决途径:
1.在线程的Join方法中加入参数timeout,如果线程阻塞,线程运行时间达到timeout时,将中止该线程。
该方法的缺点在于当生产数量不确定时,timeout的时间无法很好的确定。如果join的时间太短,可能有的进程还在运行,主进程就继续运行了。如果join的时间太长,在线程很多的情况下,将会阻塞很长的一段时间。
2.试图考虑为什么线程会阻塞。
发现在read函数中,如前所述,在每次消费之前,随机sleep 2~3秒。于是可能会出现以下的问题。
当 queue.qsize() = 1的时候,某个线程x进入了while循环,然后开始睡眠2~3秒,在这个睡眠过程中,GUI切换至其它的线程,此时由于线程x处于睡眠,并没有调用readq函数,因此queue中仍然有一个元素。以此类推,每个进程都在queue.qsize() = 1时进入了while循环,然后最早结束睡眠的线程将调用readq函数中的queue.get(1)。之后其它进程在调用queue.get(1)时,将会因为queue中缺少元素阻塞。
解决方法如下:
def read(queue):
sleep(randint(2, 4))
while queue.qsize():
lock.acquire()
readQ(queue)
lock.release()
sleep(randint(2, 4))
在while之前睡眠,且将每次消费时所需的睡眠放至readQ函数之后。可避免多个线程同时进入while循环,该改进将不会
引起阻塞。
3.Queue中的get方法,若将其参数设置为非0,则不会因为队列中没有可用元素而阻塞。将get的参数设置为0,
利用try/excep语句,当get不到数据引起异常时,excep一个break,中断线程。
Python中多线程的阻塞问题的更多相关文章
- 通过编写聊天程序来熟悉python中多线程及socket的用法
1.引言 Python中提供了丰富的开源库,方便开发者快速就搭建好自己所需要的应用程序.本文通过编写基于tcp/ip协议的通信程序来熟悉python中socket以及多线程的使用. 2.python中 ...
- Python 中多线程之 _thread
_thread模块是python 中多线程操作的一种模块方式,主要的原理是派生出多线程,然后给线程加锁,当线程结束的 时候取消锁,然后执行主程序 thread 模块和锁对象的说明 start_new_ ...
- python中多线程相关
基础知识 进程:进程就是一个程序在一个数据集上的一次动态执行过程 数据集:程序执行过程中需要的资源 进程控制块:完成状态保存的单元 线程:线程是寄托在进程之上,为了提高系统的并发性 线程是进程的实体 ...
- Python中多线程与多进程的恩恩怨怨
概念: 并发:当有多个线程在操作时,如果系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,再将时间 段分配给各个线程执行,在一个时间段的线程代码运 ...
- Python 中多线程共享全局变量的问题
写在前面不得不看的一些P话: Python 中多个线程之间是可以共享全局变量的数据的. 但是,多线程共享全局变量是会出问题的. 假设两个线程 t1 和 t2 都要对全局变量g_num (默认是0)进行 ...
- python中多线程
多线程 什么是多线程 开启线程的两种方式 进程和线程的区别 Thread对象的其他属性和方法 守护线程 死锁现象与递归锁 信号量.Event定时器 线程Queue 进程池和线程池 什么是多线程 在传统 ...
- python中多线程,多进程,多协程概念及编程上的应用
1, 多线程 线程是进程的一个实体,是CPU进行调度的最小单位,他是比进程更小能独立运行的基本单位. 线程基本不拥有系统资源,只占用一点运行中的资源(如程序计数器,一组寄存器和栈),但是它可以与同属于 ...
- python中多线程(1)
一多线程的概念介绍 threading模块介绍 threading模块和multiprocessing模块在使用层面,有很大的相似性. 二.开启多线程的两种方式 1.创建线程的开销比创建进程的开销小, ...
- python中多线程,多进程,队列笔记(一)
threading简介:If you want your application to make better use of the computational resources of multi- ...
随机推荐
- 利用pwdx查看Linux程序的工作目录
Linux中的pwdx命令,利用进程号作为参数,可以打印出指定进程号的工作目录,帮助我们区分不同的进程. pwdx <pid> [hnyundev@BJ03000036 ~]$ pwd 3 ...
- (三)Schema与数据类型优化
1.Schema schema,中文叫模式,是数据库的组织和结构 2.选择优化的数据类型 更小的通常更好:尽量使用可以正确存储数据的最小数据类型 简单就好:简单数据类型的操作通常需要更少的cpu周期. ...
- luoguP1311 选择客栈 题解(NOIP2011)
P1311 选择客栈 题目 #include<iostream> #include<cstdlib> #include<cstdio> #include<c ...
- linux性能分析工具Top
- maven项目引入spring boot依赖之后filter不生效的问题
maven的filtering没有起作用,没有把占位符给替换掉.(大家可以执行mvn clean package,看看打包后的jar里面的application.properties文件,是否有替换占 ...
- 脚本_根据 md5 校验码,检测文件是否被修改
#!bin/bash#功能:根据 md5 校验码,检测文件是否被修改#作者:liusingbon#本示例脚本检测的是/etc 目录下所有的 conf 结尾的文件,根据实际情况,您可以修改为其他目录或文 ...
- Error- spark streaming 打包将全部依赖打进去Invalid signature file digest for Manifest main attributes
spark streaming 打包将全部依赖打进去,运行jar包报错:如下 Exception in thread "main" java.lang.SecurityExcept ...
- foreach与正常for循环效率对比
foreach foreach编译成字节码之后,使用的是迭代器实现的. foreach特点: 无须获取容器大小 需要创建额外的迭代器变量 遍历期间得到的是对象,没有索引位置信息,因此不能进行赋值操作. ...
- MySQL系列之二四种隔离级别及加锁
事务 1.定义:所有操作必须成功完成,否则在每个操作中所作的所有更改都会备撤销. 2.事务的ACID 原子性atomicity 一致性consistency 隔离性isolation 持续 ...
- ivew url 的输入
1. <FormItem label="链接" prop="url"> <Input v-model="formValidate.u ...