Calling a CPU bound method in a thread

123 views
Skip to first unread message

Alok Singhal

unread,
Jul 5, 2019, 1:27:24 PM7/5/19
to gevent: coroutine-based Python network library
Hi,

I have a CPU bound method that releases the GIL for the expensive part:

def cpu_bound(*args):
    # release the GIL
    # compute
    # acquire the GIL and return a value

I am using gevent and want to call this method in a separate thread, and having the main thread be notified when the result is available (i.e., when "cpu_bound" is done).   What's the simplest way to do this?  I looked at gevent.ThreadPool, but I am not sure which method to use:

apply_cb, apply_async, spawn, ...

I am more familiar with twisted, and there I would do something like:

def cpu_bound_result(*args):
    result = cpu_bound(*args)
    reactor.callFromThread(got_result, result)

def main_thread():
    reactor. callInThread(cpu_bound_result, *args)

def got_result(result):
    # process result in main thread

Thanks!
Alok

Jason Madden

unread,
Jul 5, 2019, 1:41:15 PM7/5/19
to gev...@googlegroups.com
A rough equivalent to that would be something like this:

greenlet = gevent.get_hub().threadpool.apply_cb(cpu_bound, args, got_result)

`cpu_bound(*args)` will be run in the threadpool. When it completes, `got_result(result)` will be called in the original thread. It will be called inside the greenlet `greenlet`, which will also have `result` as its finished result; you can choose to join that greenlet at any time if you need to wait for the result at some particular point.

gevent tends to encourage a more linear, less callback oriented, flow, so `apply_cb` isn't necessarily the most common solution. Probably more common is to simply spawn a greenlet that just does `result = threadpool.apply(cpu_bound, ...)` and then proceeds to process the result "inline." Again, you can join that greenlet if you need the result at a specific point.

`threadpool.spawn()` is somewhat lower level, and returns a "passive" object that you must explicitly collect the result from and then choose how to proceed. It can work well when you know that you *must* wait at a particular point for the result.

All of these options can work well, it just depends on the rest of the structure.

~Jason

Alok Singhal

unread,
Jul 5, 2019, 3:02:45 PM7/5/19
to gev...@googlegroups.com
Thanks for the detailed reply!

On Fri, Jul 5, 2019 at 10:41 AM Jason Madden
<jason....@nextthought.com> wrote:
> gevent tends to encourage a more linear, less callback oriented, flow, so `apply_cb` isn't necessarily the most common solution. Probably more common is to simply spawn a greenlet that just does `result = threadpool.apply(cpu_bound, ...)` and then proceeds to process the result "inline." Again, you can join that greenlet if you need the result at a specific point.

`result = threadpool.apply(cpu_bound, ...)` does exactly what I want,
and is much simpler than my crazy attempts. I am still trying to get
the hang of "inline" nature of gevent!

Thanks,
Alok

Kevin Tewouda

unread,
Jul 5, 2019, 5:35:33 PM7/5/19
to gev...@googlegroups.com
Hi everyone,
I'm interested by your response Jason. In my mind, a CPU bound function should block an event-based library like gevent. I am thinking more of the use of processes that will not block the event loop and particulary at gipc which is compatible with gevent. I want to know why the threadpool.apply(..) will not block the event loop, is this because it is created in another thread different by the one used to manage the event loop?

Best regards.

--
You received this message because you are subscribed to the Google Groups "gevent: coroutine-based Python network library" group.
To unsubscribe from this group and stop receiving emails from it, send an email to gevent+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/gevent/CAPh9ZXoK5-7gSSVUEZLKEt1E%2BQwgz4Ss8jgozL08vmoebVXRUg%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.


--
Tewouda T. R. Kevin
Ingénieur informatique options génie logiciel et réseaux informatiques à 3IL
Titulaire d'un diplôme post master en télécoms à Télécoms Paris Tech
Consultant informatique pour le compte d'Alten

Jason Madden

unread,
Jul 5, 2019, 6:43:26 PM7/5/19
to gev...@googlegroups.com


> On Jul 5, 2019, at 16:35, Kevin Tewouda <lewo...@gmail.com> wrote:
>
> Hi everyone,
> I'm interested by your response Jason. In my mind, a CPU bound function should block an event-based library like gevent. I am thinking more of the use of processes that will not block the event loop and particulary at gipc which is compatible with gevent. I want to know why the threadpool.apply(..) will not block the event loop, is this because it is created in another thread different by the one used to manage the event loop?

Essentially, yes. Every event loop ("hub"; usually there's only one, in the main thread) comes equipped with a threadpool[1] that can be used to delegate non-cooperative tasks to a different operating system thread; the threadpool cooperates with the event loop to communicate tasks and results in a cooperative fashion. This can be used for CPU bound tasks, or tasks that simply don't yield to the event loop; gevent's default host resolver[2] uses the threadpool to call Python's (and hence the OS's) native resolver functions without blocking the event loop. It's possible to build different abstractions too, tailored to different use cases. Some examples are in the comments beginning at [3].

~Jason

[1] http://www.gevent.org/api/gevent.hub.html#gevent.hub.Hub.threadpool
[2] http://www.gevent.org/api/gevent.resolver.thread.html
[3] https://github.com/gevent/gevent/issues/1021#issuecomment-379401939

Kevin Tewouda

unread,
Jul 6, 2019, 1:34:00 AM7/6/19
to gev...@googlegroups.com
Hi Jason,
thank you for your explanation. Do you find cases where gipc processes is suitable to use instead of threadpool?

Best regards.

--
You received this message because you are subscribed to the Google Groups "gevent: coroutine-based Python network library" group.
To unsubscribe from this group and stop receiving emails from it, send an email to gevent+un...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Grady Player

unread,
Jul 6, 2019, 8:01:47 AM7/6/19
to gev...@googlegroups.com
Use gipc to run tasks in other processes... ie if you don’t have magic GIL handling code, you can run multiple processes and pass serialized commands and results over a pipe.

Grady


Sent from my iPhone

Kevin Tewouda

unread,
Jul 6, 2019, 4:00:46 PM7/6/19
to gev...@googlegroups.com
Hi Grady,
thank you for your answer but I already know that gipc is about running tasks in processes, my questions is to know reald wolrd use cases with gevent programs.

Best regards.


For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages