-
Notifications
You must be signed in to change notification settings - Fork 93
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
Question: How to integrate with asyncio flow? #53
Comments
On Wed, Apr 6, 2016 at 1:43 AM, Asko Soukka notifications@github.com
You should use a thread pool. Async is good for IO. It isn't good for Jim Jim Fulton |
@datakurre I don't know if I'm off topic or not, but it may be of interest. aiopyramid patches getitem for traversal to be a coroutine, so I think it's non blocking. https://github.com/housleyjk/aiopyramid/blob/master/aiopyramid/traversal.py |
@jimfulton Thanks. Python >= 3.4 AsyncIO does include "thread pool executor" for application code with configurable worker limit. So, simply runnning all ZODB accessing/manipulating code with that is then the obvious easiest solution. I'm still somewhat curious if ZODB / ZEO connection could be async (isn't database access mostly IO), but possibly it's not worth the effort. @vincentfretin It's not obvious how aiopyramid's traversal uses ZODB connection (because AFAIK each request should have their own connection for ensure MVCC). |
ZEO does use asynchronous IO to talk to it's server. It currently uses the acyncore standard module, which is Python's oldest async library. It's being updated to use asyncio. |
@jimfulton I can see that now. Thanks alot. (I've been a fan of asyncore in ZServer and have been relying on it a lot for the last few years.) |
The usecase I still don't see solved well, at least at the zope level, is where you have an IO blocking call in application code that isn't a ZODB call. For example you use urllib.geturl. The zodb client cache and it's thread is laying idle during that time urllib takes to return. In the case of a largish plone site, that's typically 1GB of RAM. |
@djay I assume your question isn't related to asyncio. I agree that having a connection tied up while an application is making a request to some external service, which is a common case today, is awkward. At ZC, we'd sometimes release and re-acquire a database connection while making an external call, but doing this was difficult. To some degree, this is an application issue, as many applications make database connections and transaction so transparent that it may not be clear how to manage them. If the external call can be queued, then that simplifies things somewhat, however handing off to a queue reliably is difficult and I'm convinced that most application (regardless of whether they use ZODB) do this incorrectly. In any case, I think it would be helpful to have an easy way to release a connection (committing a transaction, or possibly not) and get a new one later. (Perhaps it would be useful to freeze a transaction, release a connection, and restart the transaction later with a new or maybe a different connection. The savepoint machinery would probably be helpful for this.) I'm not sure what use cases would inform this. This might be an interesting topic to discuss on the ZODB list and/or the ZODB wiki. |
@djay A somewhat related thread at ZODB list https://groups.google.com/forum/m/#!topic/zodb/HpwN0RofUYQ And then our "plone.server" experiment, where we did run multiple concurrent requests on asyncio, each with their own transaction data manager, on a single ZODB connection. We didn't get far enough to see, how bad idea it really was. Probably we still try it again for some special cases like websocket connections. The early sandbox demo should give the best overview https://github.com/plone/plone.server/blob/f11921e78f34aecfb5ab6454341e035ab35d1d3c/sandbox.py On Zope 2, for that special case of urllib.geturl (or requests lib in real life), I've been using https://pypi.python.org/pypi/collective.futures : it works around the blocking issue by running the same request twice (aborting the transaction at first) and resolving the geturl calls in parallel between those requests outside the blocking worker threads. So, it's a little like "freezing" the transaction -option. Our main use case for that has been embedded views for remote data with JSON APIs. |
We were looking at c.futures to solve this too for now. Although it would be nicer if our code didn't need callbacks. if zodb If we could freeze the transaction during the coroutine call even better On Tue, 14 Jun 2016, 2:00 AM Asko Soukka notifications@github.com wrote:
|
@djay As Jim said, use of savepoint machinery for "freezing" transaction before passing the connection to another request could be worth of investigating. It could allow sharing the same connection cache between concurrent request, but also has its cost for performance: with async loop you may constantly switch between different request and that would require the connection cache to be constantly updated and rolled back from the savepoint data of each request (to prevent requests from seeing each others uncommitted changes). Anyway, it might be better to just design any asyncio-based application so that you could simply use asyncio thread pool executor with limited pool size for all ZODB operations. It would not be ideal, of course, because of the implicit nature of Persistent, no persistent objects could be accessed outside those executor threads (very much like in Zope 2). |
Yes. If you can assume that the transaction ends on each switch in the On Tue, 14 Jun 2016, 1:19 PM Asko Soukka notifications@github.com wrote:
|
Hi,
How could and should ZODB be integrated into asyncio loop based application? What kind of issued would be expected? Is there known existing work for that somewhere?
My naive assumptions are that:
Thanks a lot for your time and thoughts!
The text was updated successfully, but these errors were encountered: