Release GIL while calling `WebPAnimDecoderGetNext` by evanmiller · Pull Request #7782 · python-pillow/Pillow

@evanmiller

WebPAnimDecoderGetNext is a relatively expensive pure-C call that currently holds the Python GIL. Release it!

(Haven't tested this branch but it seemed like a straightforward change.)

@evanmiller

@radarhere

Testing with

import timeit
from PIL import Image
im = Image.open('Tests/images/iss634.webp')

def decode():
  im._decoder.reset()
  for i in range(im.n_frames):
    im._decoder.get_next()

print(timeit.timeit(decode, number=1000))

I find it hard to say that this is definitively faster than main.

@evanmiller

Hi, I don't expect it to be faster than main in a single-threaded context – the point of releasing the GIL is to allow multiple threads to call get_next() concurrently (i.e. on different images).

@evanmiller

I think you'll want a test with code like

import concurrent
import timeit
from PIL import Image
images = [Image.open('Tests/images/iss634.webp') for _ in range(100)]

def decode(im):
  im._decoder.reset()
  for i in range(im.n_frames):
    im._decoder.get_next()

with concurrent.futures.ThreadPoolExecutor(max_workers=5) as pool:
  pool.map(decode, images)

(untested but hopefully you get the idea)

radarhere

radarhere

@radarhere

You're right, that test code does demonstrate a substantial speed increase.

@evanmiller @radarhere

Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com>

@evanmiller

Updated w/ your code suggestion... I think you will have to re-approve the workflow run

radarhere

@radarhere

@hugovk

Please could you post a summary of the speed increase?

And let's include this in the release notes.

@radarhere

homm

homm approved these changes Feb 15, 2024

@radarhere

@radarhere

hugovk