Skip to content
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

Ndi-python leaves the GIL locked during all library calls #38

Open
JC3 opened this issue Sep 28, 2024 · 0 comments
Open

Ndi-python leaves the GIL locked during all library calls #38

JC3 opened this issue Sep 28, 2024 · 0 comments

Comments

@JC3
Copy link

JC3 commented Sep 28, 2024

Problem

It appears that ndi-python leaves the GIL locked during all library calls, which halts all other Python threads while NDIlib calls are being executed.

Solution

The GIL should be released during long-running, blocking library calls.

See https://docs.python.org/3/c-api/init.html#releasing-the-gil-from-extension-code for information about threading compatibility in extension libraries.

It looks like somebody has already implemented this in #22, it may be worth reviewing and potentially merging that PR then releasing an update.

Example

For example, the following program creates a thread that repeatedly calls find_wait_for_sources while continuously printing messages from the main thread (Python 3.10):

import threading
import time
import NDIlib as ndi

def p (message: str) -> None:
    print(f"[{time.time():.3f}] {message}")

def threadproc () -> None:
    finder = ndi.find_create_v2()
    while True:
        p("find_wait_for_sources enter")
        ndi.find_wait_for_sources(finder, 3000)
        p("find_wait_for_sources leave")

ndi.initialize()
thread = threading.Thread(target=threadproc)
thread.start()
while True:
    p("ding")
    time.sleep(0.1)

The expected output of this program would be "ding" every 1/10th of a second, but the actual output (notice the timestamps) is:

[1727534088.330] find_wait_for_sources enter
[1727534091.330] ding
[1727534091.330] find_wait_for_sources leave
[1727534091.330] find_wait_for_sources enter
[1727534094.331] ding
[1727534094.331] find_wait_for_sources leave
[1727534094.331] find_wait_for_sources enter
[1727534097.336] ding
[1727534097.336] find_wait_for_sources leave
[1727534097.336] find_wait_for_sources enter
[1727534100.337] ding
[1727534100.337] find_wait_for_sources leave
[1727534100.337] find_wait_for_sources enter
[1727534103.341] ding
[1727534103.341] find_wait_for_sources leave
[1727534103.341] find_wait_for_sources enter
[1727534106.341] ding
[1727534106.341] find_wait_for_sources leave

This shows that the main thread is not executing while the library is inside the find_wait_for_sources call, which is indicative of the GIL not being released during the call.

Consequence

It is impossible to use ndi-python in a threaded context. For moderately complex applications this is a showstopper, especially when performance is critical.

The only workaround is to use ndi-python in its own process and build all the IPC architecture necessary to shuffle frames around between processes, which is very cumbersome.

@JC3 JC3 changed the title Major: python-ndi leaves the GIL locked during all library calls Python-ndi leaves the GIL locked during all library calls Sep 28, 2024
@JC3 JC3 changed the title Python-ndi leaves the GIL locked during all library calls Ndi-python leaves the GIL locked during all library calls Sep 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant