From 62fa8269dca772b951fb5a6a1416a0cc2bc7219e Mon Sep 17 00:00:00 2001 From: Andrew Hamilton Date: Sun, 30 Oct 2016 12:42:50 +0100 Subject: [PATCH] Also using asyncio for the display thread. When I tried this before threading was working better. Now asyncio is doing better. Recently, exceptions were happening occasionaly in the update thread. I guess due to races. They should go away now. From now on, if a coroutine takes too long the interface will hitch. Should investigate if sync_to_filesystem is taking too long and if it can yield. There are no uses of threading now. --- fill3.py | 39 +++++++++++++-------------------------- vigil | 16 ++++++---------- 2 files changed, 19 insertions(+), 36 deletions(-) diff --git a/fill3.py b/fill3.py index 442d4a7..ec75554 100644 --- a/fill3.py +++ b/fill3.py @@ -4,13 +4,13 @@ # Copyright (C) 2015-2016 Andrew Hamilton. All rights reserved. # Licensed under the Artistic License 2.0. +import asyncio import collections import contextlib import itertools import os import signal import sys -import threading import urwid import urwid.raw_display @@ -401,6 +401,9 @@ class Placeholder: return self.widget.appearance(dimensions) +########################## + + def draw_screen(widget): appearance = widget.appearance(os.get_terminal_size()) print(terminal.move(0, 0), *appearance, sep="", end="", flush=True) @@ -433,43 +436,27 @@ def _urwid_screen(): screen.stop() -_UPDATE_THREAD_STOPPED = threading.Event() - - -def _update_screen(main_widget, appearance_changed_event): +async def _update_screen(screen_widget, appearance_changed_event): while True: - appearance_changed_event.wait() + await appearance_changed_event.wait() appearance_changed_event.clear() - if _UPDATE_THREAD_STOPPED.is_set(): - break - patch_screen(main_widget) + patch_screen(screen_widget) -def main(loop, appearance_changed_event, screen, exit_loop=None): +def main(loop, appearance_changed_event, screen_widget, exit_loop=None): appearance_changed_event.set() - update_display_thread = threading.Thread( - target=_update_screen, args=(screen, appearance_changed_event), - daemon=True) - - def exit_loop_(): - loop.stop() if exit_loop is None: - exit_loop = exit_loop_ + exit_loop = loop.stop loop.add_signal_handler(signal.SIGWINCH, appearance_changed_event.set) loop.add_signal_handler(signal.SIGINT, exit_loop) loop.add_signal_handler(signal.SIGTERM, exit_loop) + asyncio.ensure_future(_update_screen(screen_widget, + appearance_changed_event)) with terminal.hidden_cursor(): with _urwid_screen() as urwid_screen: def on_input(urwid_screen): for event in urwid_screen.get_input(): - screen.on_input_event(event) + screen_widget.on_input_event(event) loop.add_reader(sys.stdin, on_input, urwid_screen) - update_display_thread.start() - try: - loop.run_forever() - finally: - _UPDATE_THREAD_STOPPED.set() - appearance_changed_event.set() - update_display_thread.join() - # loop.close() + loop.run_forever() diff --git a/vigil b/vigil index fb54bc6..e0a223e 100755 --- a/vigil +++ b/vigil @@ -33,7 +33,6 @@ import signal import subprocess import sys import tempfile -import threading import time import docopt @@ -198,7 +197,6 @@ class Summary: self._view_widget = fill3.View.from_widget(self) self.__cursor_position = (0, 0) self.closest_placeholder_generator = None - self._lock = threading.Lock() self._cache = {} self.is_directory_sort = True self._max_width = None @@ -296,12 +294,11 @@ class Summary: yield result def get_closest_placeholder(self): - with self._lock: - try: - return self.closest_placeholder_generator.send(None) - except AttributeError: - self.closest_placeholder_generator = self._placeholder_spiral() - return self.closest_placeholder_generator.send(None) + try: + return self.closest_placeholder_generator.send(None) + except AttributeError: + self.closest_placeholder_generator = self._placeholder_spiral() + return self.closest_placeholder_generator.send(None) def appearance_dimensions(self): return self._max_path_length + 1 + self._max_width, len(self._column) @@ -919,7 +916,6 @@ def load_state(pickle_path, jobs_added_event, appearance_changed_event, screen._appearance_changed_event = appearance_changed_event screen._main_loop = loop summary = screen._summary - summary._lock = threading.Lock() summary._jobs_added_event = jobs_added_event summary._root_path = root_path log = screen._log @@ -943,7 +939,7 @@ def main(root_path, loop, worker_count=None, is_sandboxed=True, worker_count = multiprocessing.cpu_count() * 2 pickle_path = os.path.join(tools.CACHE_PATH, "summary.pickle") jobs_added_event = asyncio.Event() - appearance_changed_event = threading.Event() + appearance_changed_event = asyncio.Event() summary, screen, log, is_first_run = load_state( pickle_path, jobs_added_event, appearance_changed_event, root_path, loop)