Отправьте данные в поток Python, затем прочитайте ответ с помощью очереди

#python #multithreading #queue

Вопрос:

Довольно легко отправлять или получать данные через потоки, используя модуль очереди, когда вы делаете что-то одновременно, но я не понял, как отправить что-то в поток, а затем правильно ожидать возврата.

В приведенном ниже примере я ожидал отправить что-то потоку для обработки, а затем получить результат, но функция t.queue.get() в основном получает то, что только что отправлено выше, вместо того, чтобы ждать возвращения потока. Как я могу это обойти?

 #!/usr/bin/env python3

from threading import Thread
from queue import Queue

class MyThread(Thread):
    queue:Queue

    def __init__(self, *args, **kwargs):
        super().__init__()
        self.queue = Queue()
        self.daemon = True

    # receives a name, then prints "Hello, name!"
    def run(self):
        while True:
            val = self.queue.get()
            if not val:
                break

            self.queue.put(f'Hello, {val}!')

def main():
    t = MyThread()
    t.start()

    # sends string to thread
    t.queue.put('Jurandir')

    # expects to receive "Hello, Jurandir!",
    # but "Jurandir" is immediately returned
    ret = t.queue.get()

    print(ret)

if __name__ == '__main__':
    main()
 

Комментарии:

1. Две очереди. По одному для каждого направления (основной->рабочий, рабочий->>основной)?

2. @Аарон, не думай об этой возможности. Это сработало отлично, спасибо!

Ответ №1:

Дело в том, что вы получаете предполагаемый результат сразу из очереди, а работник все еще не добавил результат. Вы можете разделить их на «входную очередь» и «очередь результатов». А затем подождите в главном потоке, пока в очереди не появится какой-нибудь вывод.

 #!/usr/bin/env python3

from threading import Thread, Lock
from queue import Queue


class MyThread(Thread):
    def __init__(self, *args, **kwargs):
        super().__init__()
        self.input_queue = Queue()
        self.results_queue = Queue()

        self.daemon = True

    # receives a name, then prints "Hello, name!"
    def run(self):
        while True:
            val = self.input_queue.get()

            if not val:
                break

            self.results_queue.put(f'Hello, {val}!')


def main():
    t = MyThread()
    t.start()

    # sends string to thread
    t.input_queue.put('Jurandir')

    ret = t.results_queue.get()
    while ret is None:
        ret = t.results_queue.get()
    print(ret)


if __name__ == '__main__':
    main()