-
-
Notifications
You must be signed in to change notification settings - Fork 31.1k
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
Document multiprocessing.pool.ThreadPool #61342
Comments
The multiprocessing module currently provides the "multiprocessing.dummy.ThreadPool" API that exposes the same API as the public multiprocessing.Pool, but is implemented with threads rather than processes. (This is sort of documented - it's existence is implied by the documentation of multiprocessing.dummy, but it doesn't spell out "hey, stdlib ThreadPool implementation!". Given that this feature is likely useful to many people for parallelising IO bound tasks without migrating to the concurrent.futures API (or where that API doesn't quite fit the use case), it makes sense to make it a more clearly documented feature under a less surprising name. I haven't looked at the implementation, so I'm not sure how easy it will be to migrate it to a different module, but threading seems like a logical choice given the multiprocessing.ThreadPool vs threading.ThreadPool parallel. (Honestly, I'd be happier if we moved queue.Queue to threading as well. Having a threading specific data type as a top level module in its own right just makes it harder for people to find for no real reason other than a historical accident) Alternatively, we could add a "concurrent.pool" module which was little more than: from multiprocessing import Pool as ProcessPool
from multiprocessing.dummy import ThreadPool |
Given that the change could only be made to 3.4, and we already have concurrent.futures.ThreadPoolExecutor, I am not sure there is much point to such a change now. |
Thread Pools can be handy when you want to do explicit message passing, rather than the call-and-response model favoured by the futures module. |
I don't understand what you mean by "explicit message passing" and |
Future are explicitly about kicking off a concurrent call and waiting for a reply. They're great for master/slave and client/server models, but not particularly good for actors and other forms of peer-to-peer message passing. For the latter, explicit pools and message queues are still the way to go, and that's why I think a concurrent.pool module may still be useful as a more obvious entry point for the thread pool implementation. |
As far as I can see they are mostly equivalent. For instance, ApplyResult (the type returned by Pool.apply_async()) is virtually the same as a Future. When you say "explicit message passing", do you mean creating a queue and making the worker tasks put results on that queue? Why can't you do the same with ThreadPoolExecutor? |
No, I mean implementing communicating sequential processes with independent state machines passing messages to each other. There aren't necessarily any fixed request/reply pairs. Each actor has a "mailbox", which is a queue that you dump its messages into. If you want a reply, you'll include some kind of addressing info to get the answer back rather than receiving it back on the channel you used to send the message. For threads, the addressing info can just be a queue.Queue reference for your own mailbox, for multiple processes it can either be multiprocessing queue, or any other form of IPC. It's a very different architecture from that assumed by futures, so you need to drop down to the pool layer rather than using the executor model. |
AIUI an ThreadPoolExecutor object (which must be explicitly created) And if you are impementing actors on top of a thread pool then isn't To me, the obvious way to implement actors would be to create one |
Actors are just as vulnerable to the "new threads/processes are expensive" issue as anything else, and by using a dynamic pool appropriately you can amortise those costs across multiple instances. The point is to expose a less opinionated threading model in a more readily accessible way. Executors and futures are *very* opinionated about the communication channels you're expected to use (the ones the executor provides), while pools are just a resource management tool. |
I understand that a thread pool (in the general sense) might be used to amortise the cost. But I think you would probably have to write this from scratch rather than use the ThreadPool API. The ThreadPool API does not really expose anything that the ThreadPoolExceutor API does not -- the differences are just a matter of taste. |
After a question from Brandon Rhodes, I noticed that ThreadPool is actually listed in multiprocess.pool.__all__. So rather than doing anything more dramatic, we should just document the existing multiprocessing feature. As Richard says, the concurrent.futures Executor already provides a general purpose thread and process pooling model, and when that isn't appropriate, something like asyncio or gevent may actually be a better fit anyway. |
Thanks, Matt, for the documentation PR. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: