Re: Add a "block" option to Executor.submit

I must ask again about the actual necessity of adding a blocking call to
executor.submit in that particular case. If I may intervene, the issue we're discussing about is frequently encountered with asyncio: You can have an enormous queue of clients or requests, creating a coroutine for each one of them, and using asyncio.gather to finish them all. Doing so would cause your memory to spike, and bad things to happen. The way you solve it is with a semaphore mentioned earlier. It's a standard mechanism, to be used in cases of asynchronous work, regardless of the underlying library. I believe adding a blocking submit, will create a different codebase, or way of thinking, which depends on the underlying library, specifically futures.concurrent in our case, and won't offer an advantage strong enough to justify it. As of now, you use the same constructs, no matter what kind of asynchronous work you do. Why change it? Sincerely, Bar Harel

On Sep 4, 2019, at 12:37, Bar Harel <bzvi7919@gmail.com> wrote:
The way you solve it is with a semaphore mentioned earlier. It's a standard mechanism, to be used in cases of asynchronous work, regardless of the underlying library.
Is that really true for asynchronous APIs that are explicitly queue-based? After all, it’s a bit wasteful—and a bit more complicated—to put a semaphore in front of a bounded queue instead of just using the queue bounds. (And the inefficiency may be even worse in Python, because of its relatively high function call overhead, if using the semaphore requires you to pass a lambda that calls the actual function and then signals, whereas otherwise you could just pass the function itself. But then this probably isn’t a problem very often—if your tasks are so short that an extra layer of function call hurts, they’re probably too short to use with an Executor anyway…) I suppose the question is whether Executor is a queue-based API, or whether that’s an implementation detail of the two concrete executors. On the one hand, the Java API that it’s based on is definitely not explicitly queue-based; there are a zillion different kinds of executors, and some of them don’t use pools at all. But the Python API only has two executors: a thread pool and a process pool, and I think most people know they’re based on queues even if we don’t explicitly guarantee that anywhere.

On Sep 4, 2019, at 12:37, Bar Harel <bzvi7919@gmail.com> wrote:
The way you solve it is with a semaphore mentioned earlier. It's a standard mechanism, to be used in cases of asynchronous work, regardless of the underlying library.
Is that really true for asynchronous APIs that are explicitly queue-based? After all, it’s a bit wasteful—and a bit more complicated—to put a semaphore in front of a bounded queue instead of just using the queue bounds. (And the inefficiency may be even worse in Python, because of its relatively high function call overhead, if using the semaphore requires you to pass a lambda that calls the actual function and then signals, whereas otherwise you could just pass the function itself. But then this probably isn’t a problem very often—if your tasks are so short that an extra layer of function call hurts, they’re probably too short to use with an Executor anyway…) I suppose the question is whether Executor is a queue-based API, or whether that’s an implementation detail of the two concrete executors. On the one hand, the Java API that it’s based on is definitely not explicitly queue-based; there are a zillion different kinds of executors, and some of them don’t use pools at all. But the Python API only has two executors: a thread pool and a process pool, and I think most people know they’re based on queues even if we don’t explicitly guarantee that anywhere.
participants (2)
-
Andrew Barnert
-
Bar Harel