Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.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_Events_Publish Subscribe_Pypubsub - Fatal编程技术网

Python:管理由其他线程通知的事件的线程

Python:管理由其他线程通知的事件的线程,python,multithreading,events,publish-subscribe,pypubsub,Python,Multithreading,Events,Publish Subscribe,Pypubsub,我正在用Python开发一个多线程的应用程序。特别是,在此应用程序中,一个线程应该能够生成一个事件,该事件应该通知一个(或多个)线程;接收事件通知的线程应中断其执行并运行特定函数。在该服务功能结束时,他们应该返回到生成事件之前正在执行的操作 为了做到这一点,我考虑使用某种发布/订阅模块。我发现了一个非常容易使用的:。你可以找到一个关于如何使用它的非常简单的例子 顺便说一句,当我开始使用它时,我意识到它实现了我想要的功能,但只有当您只使用进程时。如果有更多线程,它将暂停整个进程(因此,其中的所有线

我正在用Python开发一个多线程的应用程序。特别是,在此应用程序中,一个线程应该能够生成一个事件,该事件应该通知一个(或多个)线程;接收事件通知的线程应中断其执行并运行特定函数。在该服务功能结束时,他们应该返回到生成事件之前正在执行的操作

为了做到这一点,我考虑使用某种发布/订阅模块。我发现了一个非常容易使用的:。你可以找到一个关于如何使用它的非常简单的例子

顺便说一句,当我开始使用它时,我意识到它实现了我想要的功能,但只有当您只使用进程时。如果有更多线程,它将暂停整个进程(因此,其中的所有线程)以运行特定例程。这实际上不是我想要的行为。不幸的是,我无法将我的应用程序从多线程更改为多进程


您知道有什么模块可以帮助我完成我在多线程应用程序中尝试完成的任务吗?谢谢。

在python中,除了通过多处理模块之外,没有真正的并发性,因为GIL不是图片的一部分

您要执行的操作需要一个事件循环,在该循环中检查事件队列并根据需要进行调度。Pypubsub可能会让您的生活变得更轻松,但对于您想要的东西来说可能有些过分(作为《pubsub》的作者,我很乐意这么说:)鉴于mp模块提供了多个流程的无缝集成,如果并发确实是您所需要的,那么真的有理由不使用它吗

您希望事件从任何线程转到一个或多个线程,这表明您可以使用任何线程都可以发布到的共享post队列、指示事件类型的数据和事件数据。另外,每个线程都有一个消息队列:线程向共享post队列发送消息,主进程事件循环检查post队列,并根据需要将事件复制到各个线程消息队列。每个线程都必须定期检查其队列并进行处理,以删除已处理的事件。每个线程都可以订阅特定事件的主进程

下面是3个相互发送消息的辅助线程的示例:

from multiprocessing import Process, Queue, Lock
from Queue import Empty as QueueEmpty
from random import randint


def log(lock, threadId, msg):
    lock.acquire()
    print 'Thread', threadId, ':', msg
    lock.release()


def auxThread(id, lock, sendQueue, recvQueue, genType):
    ## Read from the queue
    log(lock, id, 'starting')
    while True:
        # send a message (once in a while!)
        if randint(1,10) > 7:
            event = dict(type = genType, fromId = id, val = randint(1, 10) )
            log(lock, id, 'putting message type "%(type)s" = %(val)s' % event)
            sendQueue.put(event)

        # block until we get a message:
        maxWait = 1 # second
        try:
            msg = recvQueue.get(False, maxWait)
            log(lock, id, 'got message type "%(type)s" = %(val)s from thread %(fromId)s' % msg)
            if (msg['val'] == 'DONE'):
                break
        except QueueEmpty:
            pass

    log(lock, id, 'done')


def createThread(id, lock, postOffice, genType):
    messagesForAux = Queue()
    args = (id, lock, postOffice, messagesForAux, genType)
    auxProc = Process(target=auxThread, args=args)
    auxProc.daemon = True
    return dict(q=messagesForAux, p=auxProc, id=id)


def mainThread():
    postOffice = Queue()   # where all threads post their messages
    lock = Lock() # so print can be synchronized

    # setup threads:
    msgThreads = [
        createThread(1, lock, postOffice, 'heartbeat'),
        createThread(2, lock, postOffice, 'new_socket'),
        createThread(3, lock, postOffice, 'keypress'),
    ]

    # identify which threads listen for which messages
    dispatch = dict(
        heartbeat  = (2,),
        keypress   = (1,),
        new_socket = (3,),
    )

    # start all threads
    for th in msgThreads:
        th['p'].start()

    # process messages
    count = 0
    while True:
        try:
            maxWait = 1 # second
            msg = postOffice.get(False, maxWait)
            for threadId in dispatch[msg['type']]:
                thObj = msgThreads[threadId - 1]
                thObj['q'].put(msg)
            count += 1
            if count > 20:
                break

        except QueueEmpty:
            pass

    log(lock, 0, "Main thread sending exit signal to aux threads")
    for th in msgThreads:
        th['q'].put(dict(type='command', val='DONE', fromId=0))

    for th in msgThreads:
        th['p'].join()
        log(lock, th['id'], 'joined main')
    log(lock, 0, "DONE")


if __name__ == '__main__':
    mainThread()

您完全正确,该描述与pypubsub功能有相似之处,但您将只使用pypubsub的一小部分,我认为您的工作中最复杂的是两种类型的队列,pypubsub对解决这一问题没有多大帮助。一旦队列系统使用mp模块工作(根据我的示例),您就可以引入pypubsub并对其消息进行post/queue,而不是您自己植入的事件。

“挂起整个过程(因此,其中的所有线程)”--您指的是GIL还是导致“挂起”的其他东西,我的意图是让我的线程做一些事情,并在它们进行活动时打断它们;所以,我并没有真正考虑事件循环。但也许稍微改变一下我的程序结构,那就行了。而且。。。如何创建事件循环?只是一个while循环,条件为True,检查是否有新事件?无论如何,您可以发布任何代码来澄清您在消息中所写的内容,这都是非常棒的。我不知道有任何方法可以中断非主线程(即使是信号模块也只向主线程发送信号;并且只在Unix上工作)。我扩展了工作示例,hth。