From 08a9448167cf4057215e271a55d713be4e479f85 Mon Sep 17 00:00:00 2001 From: CalWelsh Date: Sat, 28 Aug 2021 15:37:25 -0500 Subject: [PATCH 1/3] Update pyav_reader.py to make generator threadsafe I had an issue where code using pyav_reader.py would randomly break and throw a "ValueError: Generator Already Executing Error"; the stack indicated that the function _gen_frames was the culprit; I added a function and a decorator (line for line copied from the sources below with one change, re-naming "next" to "__next__") that makes a non-threadsafe generator threadsafe. This resolved the issue on both Windows and Mac. Sources: https://anandology.com/blog/using-iterators-and-generators/ https://stackoverflow.com/questions/41194726/python-generator-thread-safety-using-keras --- pims/pyav_reader.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/pims/pyav_reader.py b/pims/pyav_reader.py index 2b453ee..7776075 100644 --- a/pims/pyav_reader.py +++ b/pims/pyav_reader.py @@ -27,6 +27,28 @@ def _next_video_packet(container_iter): raise ValueError("Could not find any video packets.") +class threadsafe_iter: + """Takes an iterator/generator and makes it thread-safe by + serializing call to the `next` method of given iterator/generator. + """ + def __init__(self, it): + self.it = it + self.lock = threading.Lock() + + def __iter__(self): + return self + + def __next__(self): + with self.lock: + return self.it.next() + +def threadsafe_generator(f): + """A decorator that takes a generator function and makes it thread-safe. + """ + def g(*a, **kw): + return threadsafe_iter(f(*a, **kw)) + return g + class WrapPyAvFrame(object): def __init__(self, frame, frame_no, metadata=None): self.frame_no = frame_no @@ -46,7 +68,7 @@ def to_frame(self): frame_no=self.frame_no, metadata=self.metadata) return self.arr - +@threadsafe_generator def _gen_frames(demuxer, time_base, frame_rate=1., first_pts=0): for packet in demuxer: for frame in packet.decode(): From 2ed0ac89a2d53857925e793540cf3120cd2d3ea1 Mon Sep 17 00:00:00 2001 From: Callum Welsh Date: Sat, 28 Aug 2021 19:23:31 -0500 Subject: [PATCH 2/3] Update pyav_reader.py --- pims/pyav_reader.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pims/pyav_reader.py b/pims/pyav_reader.py index 7776075..17ebdfd 100644 --- a/pims/pyav_reader.py +++ b/pims/pyav_reader.py @@ -2,6 +2,7 @@ unicode_literals) import numpy as np +import threading from pims.base_frames import FramesSequence from pims.frame import Frame From 53f2518ed01b5b651bfa759685fd25c19a9518c2 Mon Sep 17 00:00:00 2001 From: Callum Welsh Date: Tue, 7 Sep 2021 13:30:04 -0500 Subject: [PATCH 3/3] Changed self.it.next() to next(self.it) to prevent error Sometimes the self.it.next() method was breaking; looks like that method might be an artifact of older versions of Python? Fixed it to modern spec to prevent future errors. --- pims/pyav_reader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pims/pyav_reader.py b/pims/pyav_reader.py index 17ebdfd..40caa1e 100644 --- a/pims/pyav_reader.py +++ b/pims/pyav_reader.py @@ -41,7 +41,7 @@ def __iter__(self): def __next__(self): with self.lock: - return self.it.next() + return next(self.it) def threadsafe_generator(f): """A decorator that takes a generator function and makes it thread-safe.