Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/350.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python服务器:如何在确保一次只处理一个任务的同时,连续地对任务进行排队_Python_Multithreading_Object_Queue - Fatal编程技术网

Python服务器:如何在确保一次只处理一个任务的同时,连续地对任务进行排队

Python服务器:如何在确保一次只处理一个任务的同时,连续地对任务进行排队,python,multithreading,object,queue,Python,Multithreading,Object,Queue,我有两个任务,其中一个每两秒钟调用一次,另一个在随机时间调用。两者都需要访问在上一次调用完成之前无法调用的对象(如果发生这种情况,我需要手动重新启动硬件设备) 该对象来自允许通过套接字与硬件设备通信的类 为此,我创建了一个thread类,以便在后台运行所有任务,并且不会阻止其他任务。在这个类中,我实现了一个队列:两个不同的函数将任务放入队列,一个工人应该执行任务!!不同时 因为整个项目是一个服务器,所以它应该持续运行 这是我的代码,显然不起作用。如果有人知道如何解决这个问题,我会非常高兴 更新:

我有两个任务,其中一个每两秒钟调用一次,另一个在随机时间调用。两者都需要访问在上一次调用完成之前无法调用的对象(如果发生这种情况,我需要手动重新启动硬件设备)

该对象来自允许通过套接字与硬件设备通信的类

为此,我创建了一个thread类,以便在后台运行所有任务,并且不会阻止其他任务。在这个类中,我实现了一个队列:两个不同的函数将任务放入队列,一个工人应该执行任务!!不同时

因为整个项目是一个服务器,所以它应该持续运行

这是我的代码,显然不起作用。如果有人知道如何解决这个问题,我会非常高兴

更新:26.10.2020 为了让我的问题更清楚,我根据Artiom Kozyrev的答案更新了代码

import time
from threading import Lock, Thread
import threading
from queue import Queue


class ThreadWorker(Thread):
    def __init__(self, _lock: Lock, _queue: Queue, name: str):
        # daemon=False means that process waits until all threads are finished
        # (not only main one and garbage collector)
        super().__init__(name=name, daemon=False)
        # lock prevents several worker threads do work simultaneously
        self.lock = _lock
        # tasks are send from the main thread via Queue
        self.queue = _queue

    def do_work(self, job):
        # lock context manager prevents other worker threads from working in the same time
        with self.lock:
            time.sleep(3)
            print(f"{threading.current_thread().getName()}: {job * 10}")

    def run(self):
        while True:
            job = self.queue.get()
            # "poison pillow" - stop message from queue
            if not job:
                break
            self.do_work(job)

def TimeStamp(msg):
    tElapsed = (time.time() - tStart)  # Display Thread Info
    sElap = int(tElapsed)
    msElap = int((tElapsed - sElap) * 1000)
    usElap = int((tElapsed - sElap - msElap / 1000) * 1000000)
    print(msg , ': ',  sElap, 's', msElap, 'ms', usElap, 'us')

def f1():
    TimeStamp("f1 start")
    time.sleep(2)
    TimeStamp("f1 finished")

def f2():
    TimeStamp("f2 start")
    time.sleep(6)
    TimeStamp("f2 finished")

def insertf1():
    for i in range(10):
        q.put(f1())
        time.sleep(2)

def insertf2():
    for i in range(10):
        time.sleep(10)
        q.put(f2())



q = Queue()
lock = Lock()
workers = [ThreadWorker(lock, q, f"Th-worker-{i}") for i in range(5)]  # create workers
for w in workers:
    w.start()

tStart = time.time()
threading.Thread(target=insertf1, daemon=True).start()
threading.Thread(target=insertf2, daemon=True).start()
输出为:

f1起点:0秒0毫秒0秒

f1已完成:2 s 2 ms 515 us

f1起点:4s9ms335us

f1完成:6秒9秒932美国

f1起点:8秒17毫秒428美国

f2开始:10秒12毫秒794美国

f1完成:10秒28毫秒633美国

f1起点:12秒29毫秒182美制

f1已完成:14秒34毫秒411美国

f2完成:16秒19毫秒330美国


f1在f2完成之前启动,这是需要避免的。

要这样做,您需要将
队列
锁定
组合起来。锁定将阻止工作线程同时工作。查找下面的代码示例:

导入时间
从线程导入锁,线程
导入线程
从队列导入队列
类ThreadWorker(线程):
定义初始化(self,_lock:lock,_queue:queue,name:str):
#daemon=False表示进程等待所有线程完成
#(不仅仅是主处理器和垃圾收集器)
super()
#锁定防止多个工作线程同时工作
self.lock=\u lock
#任务通过队列从主线程发送
self.queue=\u队列
def do_工作(自我、工作):
#锁定上下文管理器防止其他工作线程同时工作
使用self.lock:
时间。睡眠(3)
打印(f“{threading.current_thread().getName()}:{job*10}”)
def运行(自):
尽管如此:
job=self.queue.get()
#“毒药枕头”-停止队列中的消息
如果不是工作:
打破
自我工作(工作)
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
q=队列()
lock=lock()
workers=[ThreadWorker(lock,q,f“Th worker-{i}”)表示范围(5)中的i]#创建workers
对于在职工人:
w、 开始()
#产生任务
对于范围(10)内的i:
q、 付诸表决(i)
#使用“毒枕”停止任务
对于范围内的i(len(工人)):
q、 put(无)
根据问题添加内容进行编辑(添加锁)

其主要思想是,不应在没有锁定的情况下运行f1和f2

import time
from threading import Lock, Thread
import threading
from queue import Queue


class ThreadWorker(Thread):
    def __init__(self, _lock: Lock, _queue: Queue, name: str):
        # daemon=False means that process waits until all threads are finished
        # (not only main one and garbage collector)
        super().__init__(name=name, daemon=False)
        # lock prevents several worker threads do work simultaneously
        self.lock = _lock
        # tasks are send from the main thread via Queue
        self.queue = _queue

    def do_work(self, f):
        # lock context manager prevents other worker threads from working in the same time
        with self.lock:
            time.sleep(3)
            print(f"{threading.current_thread().getName()}: {f()}")

    def run(self):
        while True:
            job = self.queue.get()
            # "poison pillow" - stop message from queue
            if not job:
                break
            self.do_work(job)


def TimeStamp(msg):
    tElapsed = (time.time() - tStart)  # Display Thread Info
    sElap = int(tElapsed)
    msElap = int((tElapsed - sElap) * 1000)
    usElap = int((tElapsed - sElap - msElap / 1000) * 1000000)
    print(msg, ': ',  sElap, 's', msElap, 'ms', usElap, 'us')


def f1():
    TimeStamp("f1 start")
    time.sleep(1)
    TimeStamp("f1 finished")
    return f"Func-1-{threading.current_thread().getName()}"


def f2():
    TimeStamp("f2 start")
    time.sleep(3)
    TimeStamp("f2 finished")
    return f"Func-2-{threading.current_thread().getName()}"


def insertf1():
    for i in range(5):
        q.put(f1)  # do not run f1 here! Run it in worker thread with Lock


def insertf2():
    for i in range(5):
        q.put(f2) # do not run f2 here! Run it in worker thread with Lock


q = Queue()
lock = Lock()
workers = [ThreadWorker(lock, q, f"Th-worker-{i}") for i in range(5)]  # create workers
for w in workers:
    w.start()

tStart = time.time()
threading.Thread(target=insertf1, daemon=True).start()
threading.Thread(target=insertf2, daemon=True).start()

如果队列中只有一个线程在使用,我不明白为什么您会担心两个作业同时运行?一个作业是现有的后台线程,一旦建立套接字连接,就会创建一个新线程:CallFromExtern()。另一个作业也应该在后台运行,以免干扰用户体验。两个作业都需要访问类似的对象,但功能不同。如果用户执行此请求,而服务器当前正在使用该对象,则硬件设备将崩溃,需要手动重新启动。因此,我需要一个队列,以便此对象是线程保存的,并且在对象函数完成之前从未调用过。您的
ControlQueue
类继承自
threading.thread
queue.queue
,同时它内部有这两个类的实例。这样的程序结构是可能的,但由于您似乎从未使用继承的
queue.queue
功能,我建议您查看设计决策,首先确定需要多少线程和队列,以及它们的角色。您不能将
f1
f2
放入队列中。您正在将调用这些函数的结果放入队列中。谢谢您的回答,但这会像我以前遇到的那样造成问题。为了测试它,我创建了两个线程:threading.Thread(target=insertf1,daemon=True).start()threading.Thread(target=insertf2,daemon=True).start()。两个线程都将函数f1(每2秒)和f2(每10秒)插入队列。f1执行需要2秒,f2执行需要6秒。现在我打印了每个任务的开始和停止时间:f1开始:4秒9毫秒335秒f1结束:6秒9毫秒932秒f1开始:8秒17毫秒428秒f2开始:10秒12毫秒794秒f1结束:10秒28毫秒633秒f1开始:12秒29毫秒182秒f1结束:14秒34毫秒411秒f2结束:16s 19 ms 330我们可以看到,f1在f2完成之前启动。@但是,您能否在问题中添加您在代码中所做的更改,以便为函数添加锁?实际上,我的示例中的线程不是
daemon=True
,否则它们将在主线程完成其工作时完成。我根据您的代码更新了主问题,包括output@BastHut我在最初的回答中添加了信息,我检查了您的代码,发现f1和f2没有带锁运行。我更改了insert1和insert2逻辑,现在它们不提供队列就绪结果,而是将函数发送给调用该函数的工作进程。请注意,您还有另一个选择,您可以用其他方式更改代码,并在f1和f2中使用Lock,然后将准备好的结果发送给工作者,而不是函数本身。