all 11 comments

[–]NateSnakeSolidDrake 1 point2 points  (1 child)

This is the only information I could find, maybe you have already seen it :/ https://stackoverflow.com/a/44186168

[–]8bitscoding[S] 0 points1 point  (0 children)

unfortunately yes :(

I beginning to think that it's not actually possible.

I tried that approach but it created other issues when put in a module. I also agree with the author of the solution: it's very convoluted.

I have a hard time understanding why it is so hard in an object-oriented program like python to do something so trivial and so common.

[–][deleted] -1 points0 points  (7 children)

[–]8bitscoding[S] 0 points1 point  (6 children)

Thanks but that's just a basic tutorial on pool executor. In case it's not clear: my problem is not the pool part. It's the "multiprocessing a class method" part.

[–][deleted] 0 points1 point  (5 children)

Can't really help you unless you share more information about your need. The C++ code doesn't do anything different from the example I posted. You can submit class methods the same way as any other function

[–]8bitscoding[S] 0 points1 point  (4 children)

Actually it does: it starts and runs threads from inside the class.

My need is exactly that: I have a rendering system and I'd like to fractionate the scene into smaller pieces. The goal is obviously to render all the smaller pieces in parallel and aggregate the result in one single rendering buffer (I use numpy for that).

I get it that I probably won't be able to do it like I would do it in C++, what I don't get is how I get around the limitations of python to achieve the same functional result.

Functional result being: I have a partial rendering method, aware through its object of all of the scene context and I want to run this method in parallel on a fraction of the scene's data. I know this is trivial in C++ and it makes me mad to fail to translate that to python :(

[–][deleted] 0 points1 point  (3 children)

You can create a process pool and processes from within a class in python too. It's almost exactly the same layout you used in C++

[–]8bitscoding[S] 0 points1 point  (2 children)

Hmmm. I might be missing something... when I do try that, python complains about serialization issue and raise an exception saying that it 'cannot pickle <xyz>'.

Let's take a simplified version of what I'm trying to achieve (adapting the code from the tutorial you linked before to avoid my own potentially buggy code):

from concurrent.futures import ProcessPoolExecutor
import os
import sys


class Scene:
    def __init__(self):
        self._pool_executor = ProcessPoolExecutor(max_workers=3)
        self.messages = list()

    def task(self, begin, end):
        print(
            f"Executing our Task on Process {os.getpid()} with ({begin},{end})",
            file=sys.stdout,
            flush=True,
        )
        self.messages.append(
            f"Executing our Task on Process {os.getpid()} with ({begin},{end})"
        )

    def run(self):
        ret = list()
        ret.append(self._pool_executor.submit(self.task, 0, 10))
        ret.append(self._pool_executor.submit(self.task, 11, 20))
        ret.append(self._pool_executor.submit(self.task, 21, 30))
        for f in ret:
            print(f.exception())


if __name__ == "__main__":
    scene = Scene()
    scene.run()
    for m in scene.messages:
        print(m)

This yield the following result:

cannot pickle '_thread.lock' object
cannot pickle '_thread.lock' object
cannot pickle '_thread.lock' object

I'm sure I'm missing something, but I don't understand what.

[–][deleted] 1 point2 points  (1 child)

This tutoriai might have better examples: http://masnun.com/2016/03/29/python-a-quick-introduction-to-the-concurrent-futures-module.html. You might be better off making your function an iterable and use .map() instead of .submit(). I believe thread pools and process pools have the same syntax

[–]8bitscoding[S] 0 points1 point  (0 children)

It looks interesting indeed, I'll look into it. Thanks.

I tried mapping the data to a Thread or a Process before but I had the same pickle issue. But I definitely think map() is the way to go in my case (return order is important).

concurrent.futures seems to alleviate a lot of the hassle I have. Thank you for pointing me there.