Нишката на Python никога не стартира, ако run() съдържа yield from

Python 3.4, опитвам се да направя сървър, използвайки модула websockets (преди това използвах обикновени сокети, но исках да направя javascript клиент), когато се натъкнах на проблем (защото очаква async, поне ако примерите трябва да бъдат доверен, който не съм използвал преди). Threading просто не работи. Ако изпълня следния код, лентата никога няма да бъде отпечатана, докато ако коментирам реда с yield from, той работи според очакванията. Така че yield вероятно прави нещо, което не разбирам съвсем, но защо дори никога не се изпълнява? Трябва ли да инсталирам python 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 или е глупаво да го правя? Първоначално имах нишка за всеки клиент, за да видя дали има какво да получи, но мога ли просто да ги превърна в нормални обекти, ако използвам async?   -  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)

Като се има предвид това, ако искате да стартирате своя цикъл на събития от друга нишка, можете да го направите по следния начин:

импортиране на asyncio

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