Поток Python никогда не запускается, если run() содержит yield from

Python 3.4, я пытаюсь создать сервер с помощью модуля веб-сокетов (ранее я использовал обычные сокеты, но хотел создать клиент javascript), когда столкнулся с проблемой (потому что он ожидает асинхронность, по крайней мере, если примеры должны быть доверенный, которым я раньше не пользовался). Поток просто не работает. Если я запущу следующий код, bar никогда не будет напечатан, тогда как если я закомментирую строку с помощью yield from, она будет работать, как и ожидалось. Итак, yield, вероятно, делает что-то, чего я не совсем понимаю, но почему он даже не выполняется? Должен ли я установить питон 3.5?

import threading

class SampleThread(threading.Thread):
    def __init__(self):
        super(SampleThread, self).__init__()
        print("foo")

    def run(self):
        print("bar")
        yield from var2

thread = SampleThread()
thread.start()

person fdagpigj    schedule 17.12.2016    source источник
comment
вы не можете использовать yield из подпрограммы запуска, которая должна вечно зацикливаться/делать что-то, а не возвращать/выдавать что-то.   -  person Jean-François Fabre    schedule 18.12.2016
comment
мой главный вопрос был, почему? Но похоже, что ответ кроется в том, что yield автоматически превращает всю функцию, так сказать, в создателя генератора. Но как мне использовать asyncio вместе с threading, или это глупо? Изначально у меня был поток для каждого клиента, чтобы узнать, есть ли у них что-то для получения, но могу ли я просто превратить их в обычные объекты, если я использую асинхронность?   -  person fdagpigj    schedule 18.12.2016
comment
Да, глупый способ в 99% случаев. Обычно асинхронная программа должна иметь единственный цикл событий в основном потоке + пул потоков, доступный loop.run_in_executor(). Но если вам это действительно нужно — запустите новый цикл событий явно в своем потоке.   -  person Andrew Svetlov    schedule 18.12.2016


Ответы (1)


Это неправильный способ обработки многопоточности. run не является ни генератором, ни сопрограммой. Следует отметить, что цикл событий asyncio определен только для основного потока. Любой вызов asyncio.get_event_loop() в новом потоке (без предварительной установки его с помощью asyncio.set_event_loop() вызовет исключение.

Прежде чем рассматривать запуск цикла событий в новом потоке, вы должны сначала проанализировать, действительно ли вам нужен цикл событий, работающий в своем собственном потоке. Он имеет встроенный исполнитель пула потоков по адресу: loop.run_in_executor(). Это возьмет пул из concurrent.futures (либо ThreadPoolExecutor, либо ProcessPoolExecutor) и обеспечит неблокирующий способ запуска процессов и потоков непосредственно из объекта цикла. Таким образом, они могут быть await-ed (с синтаксисом Python3.5).

При этом, если вы хотите запустить свой цикл событий из другого потока, вы можете сделать это так:

импортировать асинхронный

class LoopThread(threading.Thread):
    def __init__(self):
        self.loop = asyncio.new_event_loop()

    def run():
        ayncio.set_event_loop(self.loop)
        self.loop.run_forever()

    def stop():
        self.loop.call_soon_threadsafe(self.loop.stop)

Отсюда вам все еще нужно использовать потокобезопасный способ создания задач и т. д. Часть кода в этом потоке можно использовать, хотя у меня не было большого успеха с ним: python asyncio, как создавать и отменять задачи из другого потока

person Goodies    schedule 19.12.2016