在使用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中多线程的阻塞问题的更多相关文章

  1. 通过编写聊天程序来熟悉python中多线程及socket的用法

    1.引言 Python中提供了丰富的开源库,方便开发者快速就搭建好自己所需要的应用程序.本文通过编写基于tcp/ip协议的通信程序来熟悉python中socket以及多线程的使用. 2.python中 ...

  2. Python 中多线程之 _thread

    _thread模块是python 中多线程操作的一种模块方式,主要的原理是派生出多线程,然后给线程加锁,当线程结束的 时候取消锁,然后执行主程序 thread 模块和锁对象的说明 start_new_ ...

  3. python中多线程相关

    基础知识 进程:进程就是一个程序在一个数据集上的一次动态执行过程 数据集:程序执行过程中需要的资源 进程控制块:完成状态保存的单元 线程:线程是寄托在进程之上,为了提高系统的并发性 线程是进程的实体 ...

  4. Python中多线程与多进程的恩恩怨怨

    概念: 并发:当有多个线程在操作时,如果系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,再将时间 段分配给各个线程执行,在一个时间段的线程代码运 ...

  5. Python 中多线程共享全局变量的问题

    写在前面不得不看的一些P话: Python 中多个线程之间是可以共享全局变量的数据的. 但是,多线程共享全局变量是会出问题的. 假设两个线程 t1 和 t2 都要对全局变量g_num (默认是0)进行 ...

  6. python中多线程

    多线程 什么是多线程 开启线程的两种方式 进程和线程的区别 Thread对象的其他属性和方法 守护线程 死锁现象与递归锁 信号量.Event定时器 线程Queue 进程池和线程池 什么是多线程 在传统 ...

  7. python中多线程,多进程,多协程概念及编程上的应用

    1, 多线程 线程是进程的一个实体,是CPU进行调度的最小单位,他是比进程更小能独立运行的基本单位. 线程基本不拥有系统资源,只占用一点运行中的资源(如程序计数器,一组寄存器和栈),但是它可以与同属于 ...

  8. python中多线程(1)

    一多线程的概念介绍 threading模块介绍 threading模块和multiprocessing模块在使用层面,有很大的相似性. 二.开启多线程的两种方式 1.创建线程的开销比创建进程的开销小, ...

  9. python中多线程,多进程,队列笔记(一)

    threading简介:If you want your application to make better use of the computational resources of multi- ...

随机推荐

  1. _groovy

    _groovy与beanshell类似,只是它执行的是apache groovy脚本,并返回结果. 如果定义了属性 “groovy.utilities”,属性将会被脚本引擎加载,这样就可以定义一些通用 ...

  2. 《剑指offer》面试题5 从尾到头打印链表 Java版

    书中方法一:反转应该立刻想到栈,利用一个栈完成链表的反转打印,但是用了额外的O(n)空间. public void printFromTail(ListNode first){ Stack<Li ...

  3. 数据溢出-varchar类型

    数据溢出一.varchar(65535)1.在charset=latin1,因为有额外的开销,实际只能存65532 CREATE table demo( a ) )charset=latin1 eng ...

  4. Codeforces 1162D Chladni Figure(枚举因子)

    这个题好像可以直接暴力过.我是先用num[len]统计所有每个长度的数量有多少,假如在长度为len下,如果要考虑旋转后和原来图案保持一致,我们用a表示在一个旋转单位中有几个长度为len的线段,b表示有 ...

  5. CodeChef 3-Palindromes(Manacher+dp)

    3-Palindromes   Problem code: PALIN3   Submit All Submissions   All submissions for this problem are ...

  6. MapReduce数据格式化------<一>

    引言: 我们知道:在MapReduce程序的Map阶段,需要有数据输入,而由于数据往往大小不规则,所以在数据输入Mapper之前,需要根据数据的特点和业务逻辑对数据进行格式化.这一步的格式化被称为:I ...

  7. 并行开发 8.用VS性能向导解剖你的程序

    原文:8天玩转并行开发——第八天 用VS性能向导解剖你的程序 最后一篇,我们来说说vs的“性能向导",通常我们调试程序的性能一般会使用Stopwatch,如果希望更加系统的了解程序,我们就需 ...

  8. 工作流引擎 springmvc SSM 流程审批 Java Activiti 后台框架源码

    工作流模块  1.模型管理    :web在线流程设计器.预览流程xml.导出xml.部署流程 2.流程管理    :导入导出流程资源文件.查看流程图.根据流程实例反射出流程模型.激活挂起 3.运行中 ...

  9. windows10安装docker[含百度网盘docker安装包]

    在win10上安装 docker(比较简单) 安装步骤: 现在 Docker 有专门的 Win10 专业版系统的安装包,需要开启Hyper-V. 1.开启 Hyper-V 程序和功能 启用或关闭Win ...

  10. CSAW CTF Qualification Round 2018 - shell->code

    原题 Linked lists are great! They let you chain pieces of data together. nc pwn.chal.csaw.io 9005 链接:h ...