Skip to content Skip to sidebar Skip to footer

Pickling Python Function Fails With Processpoolexecutor In A Decorator

So I asked this question and tried the ProcessPoolExecutor approach. I used the decorator suggested the following way: Running Image Manipulation in run_in_executor. Adapting to mu

Solution 1:

Decorators typically produce wrapped functions that aren't easy to pickle (serialize) because they contain hidden state. When dealing with multiprocessing, you should avoid decorators and send ordinary global functions to run_in_executor. For example, you could re-write your executor decorator into a utility function:

_pool = concurrent.futures.ProcessPoolExecutor()
 
async def exec_async(fn, *args):
    loop = asyncio.get_event_loop()
    returnawaitloop.run_in_executor(_pool, fn, *args)

Instead of decorating a function with executor, you can just await it using await exec_async(some_function, arg1, arg2, ...). Likewise, you can rewrite the pil decorator into another utility:

def pil(image, transform):
    img = PILManip.pil_image(image)
    if img.format == "GIF":
        frames = []
        for frame in ImageSequence.Iterator(img):
            res_frame = transform(frame)
            frames.append(res_frame)
        return PILManip.pil_gif_save(frames), "gif"
    elif img.format in ["PNG", "JPEG"]:
        img = transform(img)
        return PILManip.pil_image_save(img), "png"
    else:
        raise BadImage("Bad Format")

The implementation of blur now becomes an ordinary function which callspil, and which can be safely passed to exec_async:

defblur(image):
    deftransform(frame):
        frame = frame.convert("RGBA")
        return frame.filter(ImageFilter.BLUR)
    return pil(image, transform)
 
@router.get("/blur/", responses=normal_response)asyncdefblur_image(url: str):
    byt = await Client.image_bytes(url)
    img, image_format = await exec_async(blur, byt)
    return Response(img.read(), media_type=f"image/{image_format}")

Note: the above code is untested.

Post a Comment for "Pickling Python Function Fails With Processpoolexecutor In A Decorator"