I agree that is counter to the basic philosophy, though there are potential use cases where it may be unavoidable to use threads.  It seems the best solutions when it is then are to use run_in_executor, which automatically handles the waking up of the loop.  While the Queue object doesn't work with threads, though there does seem to be a library janus which provides a thread-capbable queue object which could be another solution.


-----Original Message-----
From: Guido van Rossum <guido@python.org>
To: Brian Allen Vanderburg II <brianvanderburg2@aim.com>
Cc: Python-Ideas <python-ideas@python.org>
Sent: Thu, Feb 13, 2020 1:18 am
Subject: Re: [Python-ideas] Asyncio Future.set_result_threadsafe

Sharing futures between threads like that goes counter to asyncio's basic philosophy (which is not to use threads :-).

You already showed the solution: future._loop.call_soon_threadsafe(future.set_result, ...). If that's unacceptable for you, maybe you can wrap the future in a wrapper class that calls call_soon_threadsafe.

On Wed, Feb 12, 2020 at 8:51 PM Brian Allen Vanderburg II via Python-ideas <python-ideas@python.org> wrote:
Currently asyncio.futures.Future.set_result will result in any callbacks
being scheduled using loop.call_soon instead of
loop.call_soon_threadsafe. However in situations where the future's
result is set from a different thread, the loop might not wake up as a
result of this if it is currently sleeping.


def compute_something(...):
    loop = asyncio.get_event_loop()
    future = loop.create_future()
    manager.run_computation(future, ...) # add the computation to a
thread that is running it
    return future

async def compute_stuff():
    result = await compute_something(...)

loop = asyncio.get_event_loop()
loop.run_until_complete(compute stuff())
loop.close()


The reasoning behind it is after yielding the Future object, the ready
list of the event loop is empty so when waiting for selectors the
timeout value is None and it just waits. When the other thread calls
set_result, the loop ready list will get updated, but it's still waiting
on selectors.  The other thread could call
future._loop.call_soon_threadsafe(future.set_result, ...), which writes
some bytes to a socket in order to wake the even loop.

I'm aware there are other ways to do things like this (queues,
executors, etc). It just seems that, regardless of any method used, the
code holding the future with the purpose of setting a result on it
should be able to be blind to other implementation details. 
future.set_result should be all it needs to know to call even if from
another thread, or if not, a method like future.set_result_threadsafe,
which would hide the details of the loop.call_soon/call_soon_threadsafe


_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-leave@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/PLKYKFWM4EM7DHUHWOBDU2JSJM57X7GM/
Code of Conduct: http://python.org/psf/codeofconduct/


--
--Guido van Rossum (python.org/~guido)