2016-03-04 110 views
0

我正在通过一个简单的多线程教程。其中有10个线程创建相应的处理20名工人。我明白了一个线程如何处理一个worker,并且有10个线程并行运行,服务于20个驻留在优先级队列中的worker。 但我的问题是,如果一个线程已完成为指派的工作人员提供服务,并且有9个线程仍在为其工作人员提供服务,会发生什么情况。python多线程使用python

我想创建一个脚本,如果一个线程的工作结束,那么它应该获取驻留在队列中的其他工作人员。

这里是我的代码: -

import threading 
from queue import PriorityQueue 
import time 

print_lock = threading.Lock() 

q = PriorityQueue() 

def threader(): 
    i = 0 
    while True: 
     worker = q.get() 
     exampleJob(worker) 
     q.task_done() 



for x in range(10): 
    t = threading.Thread(target = threader) 
    t.deamon = True 
    t.start() 

start_time = time.time() 

for worker in range(1,20): 
    q.put(worker) 

def exampleJob(worker): 
    if(worker ==1): 
     time.sleep(0.5) 
    else: 
     time.sleep(5) 

    with print_lock: 
     print(threading.current_thread().name,worker) 

q.join() 


print('Entire job took:', time.time()-start_time) 

在上面的代码中,我创建的0.5睡眠的工人1,但其余有5秒的睡眠,如果我执行这个脚本,线程1处理工作者1和等待直到所有其他9个线程完成其工作。 我想如果线程1完成了工作,它应该采用工号11来处理。上面的代码

输出为: -

Thread-1 1 
Thread-3 3 
Thread-5 5 
Thread-4 4 
Thread-2 2 
Thread-6 6 
Thread-10 10 
Thread-7 7 
Thread-9 9 
Thread-8 8 
Thread-1 11 
Thread-3 12 
Thread-5 13 
Thread-4 14 
Thread-2 15 
Thread-6 16 
Thread-10 17 
Thread-7 18 
Thread-9 19 
Entire job took: 10.137013912200928 

回答

0

你创造了10个线程,并开始他们每个人(for x in range(10):)的。

每个线程都会尝试从队列中检索一个对象。由于queue's get method块,实际上首先调用.get()的第一个线程将阻塞,直到将某些内容放入队列中。下一个线程将阻塞,直到.get()在前一个线程中返回。这仅仅是因为该Queue类的文档说它是线程安全的。如果一个类或数据结构没有记录(并且实际上是正确实现的)是线程安全的,那么所有的赌注都是关闭的。

请注意,除非您自己明确编写必要的同步代码(例如使用锁定或类似代码),否则线程不能保证顺序。所以不能保证线程1是第一个真正开始执行并输入.get()方法的人。

当你开始每一个10个线程后,你就开始把数字放入队列中。随着数字到达队列中,线程将在某个时刻唤醒并接收它们。虽然PriorityQueue中的值的顺序是有保证的,但不保证从队列接收的线程的顺序。

当它计划运行时,每个线程将休眠指定的时间量。请注意,sleep()对调用函数和从函数返回之间所经过的实际时间量几乎没有提供保证。

实际挂起时间可能会小于所请求的时间,因为任何捕获的信号都会在执行该信号的捕获程序后终止睡眠()。而且,由于系统中的其他活动的调度,中止时间可能比任意数量所要求的更长。

在版本3.5中进行了更改:即使睡眠被信号中断,除非信号处理程序引发异常(请参阅PEP 475的基本原理),该函数现在至少会睡眠秒。

所以每个线程将开始它的睡眠周围的同时,但不完全,并且将唤醒的同时各地,因为睡眠时间是一样的,并且被安排各地执行同时。请注意,线程可以在执行过程中的任何时刻挂起,并且可以恢复另一个线程。在单核系统上,只有一个线程可以在任何给定时间实际执行,并且所有其他线程都在等待调度程序暂停正在执行的线程并切换到另一个线程。在多核系统上,单独的线程可以同时在不同的核心上运行,但每个核心一次最多只能运行一个线程。

当你的线程从.sleep()返回后,他们会争取获得锁定。这会导致每个人在另一个开始打印之前完成打印输出。这是一件好事,所以输出不会在中间交错。无法保证线程获取锁定的顺序。保证是一次只有一个线程锁定。如果锁定可用,则线程将立即获取该锁定,但如果不是,则等待。

在您提供的输出中,线程1确实处理了“worker”11.但是,这并不能保证,除非您确保在线程1在队列上调用.get()之前不启动任何其他线程。在你的程序中,虽然没有保证,但是相当可预测的是,无论线程进程“worker”1是否也会处理“worker”11,因为睡眠持续时间非常短,很可能它将在队列中排在第二位,而另一个仍有9个线程仍在拨打.sleep()。它不能保证,因为调度程序可能不会实际调度该线程执行;该线程可能会保持挂起状态,并且不同的线程可能会到达从该队列中检索下一个项目的位置。

希望对您提供的程序的这种解释是有帮助的。

+0

嗨,感谢您的详细解释。 正如你所说,为了达到同步我必须在锁上工作,我的问题仍然是一样的,我如何同步这些线程以便Th1选择工人1等等。在Th1完成工作后不久,它应该选择下一名优先级较高的工作人员。 –