How can I interrupt a read file operation? For example I'm trying to read a big tiff file on network drive and it can sometime take a long time. I want to be able to cancel the reading operation on a button click for example. I read about threading but I can't use an event here since it's not a loop, but a single read operation, and I can't periodically check for a stop event..
def start_reading(path):
thread = threading.Thread(target=read_tiff(path))
thread.start()
def read_tiff(path):
start = time.time()
print('Start reading\n')
im = cv2.imread(file)
print('Read finished: %.3f' % (time.time() - start))
def stop_reading():
....
file = 'random.tiff'
root = tk.Tk()
start_button = tk.Button(root, text="Start Reading", command=lambda: start_reading(file))
start_button.pack()
stop_button = tk.Button(root, text="Stop Reading", command=stop_reading)
stop_button.pack()
root.mainloop()
You can still use a threading.Event
object to signal to the worker thread (read_tiff
) if it should early exit in case of a user pressing the stop button. Since cv2.imread
is blocking, I suggest streaming the network file into a tempory bytebuffer
in increments of small chunks. That way the worker can continue checking the stop
event, and early exit if requested by the user. In case the image downloads before the user presses the stop button, you can use numpy
and cv2
APIs to decode the byte buffer back to a cv2
image object.
import cv2
import threading
import time
import numpy as np
import tkinter as tk
def start_reading(path, stop):
stop.clear()
thread = threading.Thread(target=read_tiff, args=(path, stop))
thread.start()
def read_tiff(path, stop):
print("read thread started")
start = time.monotonic()
buf = bytearray()
with open(path, 'br') as f:
print('Start reading\n')
chunk = f.read(1024)
while chunk and not stop.is_set():
buf.extend(chunk)
chunk = f.read(1024)
if stop.is_set():
print("Thread timed out")
return
arr = np.frombuffer(buf, np.uint8)
img = cv2.imdecode(arr, cv2.IMREAD_COLOR)
# write to output file to verify it works
cv2.imwrite('output.tiff', img)
print('Read finished: %.3f' % (time.monotonic() - start))
file = 'random.tiff'
root = tk.Tk()
stop_event = threading.Event()
start_button = tk.Button(
root,
text="Start Reading",
command=lambda: start_reading(file, stop_event),
)
start_button.pack()
stop_button = tk.Button(
root,
text="Stop Reading",
command=lambda: stop_event.set()
)
stop_button.pack()
root.mainloop()