-
Notifications
You must be signed in to change notification settings - Fork 142
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
Possible race condition in get_asynclib when threading #210
Comments
Can you give me any clues as how to repro this? How are you using threads? |
My best guess is that the race condition occurs when two threads check whether The first thread (T1) checks Given that this is in fact the problem, I can see two solutions:
|
Are you by any change spawning threads as side effects of imports? |
I suppose it's possible that a package I depend on does, but in my code, I am not. |
Could you check? |
It would be easier if I tried to patch |
I guess it wouldn't hurt. But import conflicts like this simply shouldn't happen unless there was a circular import somewhere. |
I'm not sure that's true because anyio/src/anyio/_core/_eventloop.py Line 113 in 11434a9
|
Are you running async code in multiple threads? |
Yes |
That is highly unorthodox. Can you describe why this is done? I can see the imports being a problem there. |
I agree. It's a little hard to explain, but at a high level I have an async framework for creating interactive UI elements and it needs to work with the Flask web server (which is not async). To do that I have to create to different threads each of which is running an event loop. I can point you to the code in question, but I don't think that will be very helpful. |
Please do point me to that code, it just might be. |
Put even more succinctly, I'm trying to make an async framework play nicely with a sync framework and it requires a bit of nastiness with threads. |
Sure, but that's where blocking portals come in. |
https://github.com/idom-team/idom/blob/main/idom/server/flask.py#L184-L250 This then calls a bit of code that opens task groups: https://github.com/idom-team/idom/blob/main/idom/core/dispatcher.py#L36-L49 |
blocking portals? |
By the way, code like this will likely lead to problems: https://github.com/idom-team/idom/blob/main/idom/core/dispatcher.py#L37-L39 |
So normally would have only one thread running the event loop, and then use blocking portals to call async code in that event loop from worker threads, thus avoiding any concurrency issues with dynamic imports. |
This is really helpful. I don't have time to fully understand or try these suggestions out now, but I'll definitely be looking into them. Feel free to close this for now. I'll re-open if I'm unable to figure it out on my own. |
Thanks! |
NB, another possibility is to use quart (or quart-trio). It's async and mostly-compatible with Flask. No more threads. |
Definitely an option for others. Unfortunately in my case though I'm trying to integrate with Dash which uses Flask. |
I think I've been experiencing this same issue with a FastAPI app. The app is kicked off with this code, which is in import asyncio
from threading import Thread
from gunicorn.app.wsgiapp import WSGIApplication
class StandaloneApplication(WSGIApplication):
def __init__(self, app_uri, options=None):
self.options = options or {}
self.app_uri = app_uri
super().__init__()
def load_config(self):
config = {
key: value
for key, value in self.options.items()
if key in self.cfg.settings and value is not None
}
for key, value in config.items():
self.cfg.set(key.lower(), value)
def run_web():
options = {
"bind": "myhostname:8765",
"workers": 3,
"worker_class": "uvicorn.workers.UvicornWorker",
}
StandaloneApplication("myapp.main:app", options).run()
async def _run_asyncio():
await thing_that_runs_in_background_as_long_as_this_process_is_alive()
def run_asyncio():
asyncio.run(_run_asyncio())
def run():
asyncio_thread = Thread(target=run_asyncio, daemon=True)
asyncio_thread.start()
run_web()
asyncio_thread.join() One of my stack traces looks like this:
And another one looks like this:
I'm not getting the same error each time. It's intermittent, sometimes I get an I've recently added Can anyone here confirm that the errors I'm seeing appear to be this race condition issue? Sure looks like it to me, as And can anyone suggest anything else I might want to do, to resolve the issue, other than chucking |
I'm not quite sure how to reproduce and it's also possible I'm doing something wrong that's causing this. I figured I'd open this just so anyone else that might be experiencing something similar has something to try as a fix, so feel free to close if there's not enough info or shouldn't be solved in AnyIO.
Here's the traceback I was seeing when trying to use
anyio
from a thread:This seemed very weird until I got another traceback claiming that
anyio._backends._asyncio
was partially initialized which clued me into the fact that this was a race condition.The solution was just to import
anyio._backends._asyncio
at the top of my file before starting the thread that importsanyio
.The text was updated successfully, but these errors were encountered: