-
-
Notifications
You must be signed in to change notification settings - Fork 344
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
from_thread.run(_sync)?
fails in any thread running Trio
#2534
Comments
I agree that the check is more zealous than it strictly needs to be. I don't think the idea of multiple Trio threads was contemplated when I'm curious what you're doing that requires multiple Trio threads anyway -- we've considered the possibility but hadn't come across anyone with a concrete use case! |
Isn't it fairly trivial to cross call from one Trio thread to the other? If you don't want the overhead, well, creating something like However IMHO relaxing the rules about not calling any |
tl;dr tl;dra use-case for sync cross-calling between multiple threads running Trio event loops is agronholm/anyio#341. tl;dra (short-lived) sync function can call a (short-lived) async function by running it in a temporary *: or rather, cases that
to my knowledge there is not a better way to accomplish this than sync cross-calling support. i'd be very happy to be wrong here though. it's currently possible for Trio users to roll their own sync cross-calling support using only public other people have been using AnyIO's API for this use-case for some time, but it seems they did not realize that it only works on the AsyncIO backend and not on Trio (reference) (AnyIO issue). the problemoften times we want to run some async code in a blocking way within a sync function. for example, suppose we have a (short-lived) sync function (call it
calls to
(note:
why not use
|
async cross-calling unfortunately wouldn't be useful for this use-case; it needs to be sync (see above). i do think that async cross-calling would be a cool interface to have, especially if a GIL-free Python implementation ever becomes mainstream and running multiple Trio threads becomes useful for performance. with mandatory GIL's in place still, i can't currently think of a use-case for it though. |
sorry—by "thread running Trio"/"Trio thread" i meant "thread running a Trio event loop", not "thread started by
yes, but if the hypothetical |
after some more digging, this issue is a duplicate of #2191. apologies for not searching the tracker thoroughly enough before opening this. i will update the corresponding PR's newsfragment to reference the lower issue number. i'll leave this duplicate open currently since there is ongoing discussion, but let me know if discussion should move to #2191 instead. |
@gschnaffer thank you for the extremely detailed response! I'm convinced :-) Would you also benefit from I agree that greenback is somewhat dangerous in that it can violate "no task switches can occur in a synchronous function" assumptions. I don't think it is particularly hazardous otherwise, unless you consider greenlets in general to be hazardous; the async support in SQLAlchemy uses the same technique, and I use greenback in production at my day job. |
@oremanj awesome! i wasn't sure if the detailed message would be helpful or a nuisance and i'm glad it's being helpful.
ignoring asyncio support, though, our main use-case for sync cross-calling is for something that with SyncConnection(ip_addr_or_hostname, ...) as remote_server:
# a `SyncConnection` wraps a `Connection` and its nursery, multiplexer, etc. that run in
# a background thread scoped to this `with` block.
foo_ret = remote_server.foo() # this calls a coro in the bg thread.
something()
bar_ret = remote_server.bar() # this calls a coro in the bg thread.
... i believe that said, allowing nested event loops would clearly be quite useful in only-Trio (not AnyIO) code: def foo():
# foo() works in a fully sync context per usual, but it also no longer breaks when
# called under a running event loop!
bar_ret = trio.run(bar, allow_nested=True)
... and i'd happily use this feature in the situations where we use Trio over AnyIO. regarding greenback violating that assumption, do you think a note should be added to the "what won't work" section of the greenback readme? most of the time, greenback's violation of that assumption is not problematic, but i have had it cause a bug in real code once (and it was a huge pain to debug given that it violates the should-be-safe-to-assume "1st law of async/await" and is flaky to reproduce (it depends on scheduling order)). Footnotes
|
hi!
from_thread.run(_sync)?
uses a heuristic to prevent the user from accidentally deadlocking their event loop by writing code like https://github.com/python-trio/trio/pull/1574/files#r435039316.the heuristic is currently much more aggressive than is required to prevent this deadlock, however. it has the side-effect1 of preventing one from calling
from_thread.run(_sync)?
in any thread running trio, even though such calls are almost always safe and deadlock-free.it would be useful to be able to call
from_thread.run(_sync)?
from trio threads2, but the current heuristic blindly prevents this. i'd like to propose relaxingfrom_thread.run(_sync)?
to allow callingfrom_thread.run(_sync)?
from trio threads. (one use-case of this is agronholm/anyio#525.)Footnotes
citing the
RuntimeError
s reported infrom_thread.run(_sync)?
's docstrings, this would appear to be an unintended side-effect of the current heuristic. ↩for example in order to call
Nursery.start_soon
in a thread-safe manner. ↩The text was updated successfully, but these errors were encountered: