# HG changeset patch # User Alain Leufroy # Date 1576872099 -3600 # Fri Dec 20 21:01:39 2019 +0100 # Node ID 305ef1b4bb16ddfc4bded0d88ceb693c5c943000 # Parent 036e3ee2ce42fa89809fccd142009c30db98d392 limit number of async processes using `config.PRCESSES_NB` diff --git a/lairucrem/config.py b/lairucrem/config.py --- a/lairucrem/config.py +++ b/lairucrem/config.py @@ -1,3 +1,5 @@ +import asyncio +import multiprocessing import re from pathlib import Path @@ -514,12 +516,23 @@ KEYBINDINGS = [] +# Optimal: > 6 +PROCESSES_NB = multiprocessing.cpu_count() - 1 + def has_mouse_keybindings(): return 'mouse' in KEYBINDINGS +PROCESSES_SEMAPHORE = None + + # Load user defined configuration CONFIG_FILE_PATH = Path('~/.config/lairucrem/config.py').expanduser() if CONFIG_FILE_PATH.exists(): exec(CONFIG_FILE_PATH.read_text()) + + +if PROCESSES_SEMAPHORE is None: + # Do not overwrite PROCESSES_SEMAPHORE set from the user's config file. + PROCESSES_SEMAPHORE = asyncio.Semaphore(PROCESSES_NB + 1) diff --git a/lairucrem/controler.py b/lairucrem/controler.py --- a/lairucrem/controler.py +++ b/lairucrem/controler.py @@ -106,11 +106,12 @@ async def _wait(self): await super()._wait() first = True - async for widget in self: - if first: - self.clear(full=True) - first = False - self.append(widget) + async with config.PROCESSES_SEMAPHORE: + async for widget in self: + if first: + self.clear(full=True) + first = False + self.append(widget) if first: # nothing fetched self.clear(full=True) urwid.emit_signal(self, 'completed') @@ -629,6 +630,19 @@ self._diff.filename = filename self._diffstat.filename = filename + async def _wait(self): + # Load task is specific order to ensure that prefered sections + # appears quickly (PROCESSES_SEMAPHORE may delay a few of + # them). + await asyncio.gather( + self._diff.wait(), + self._summary.wait(), + self._description.wait(), + self._diffstat.wait(), + self._summaryextra.wait(), + ) + urwid.emit_signal(self, 'completed') + class patchlistbox( mixin.filterable_listbox, @@ -771,12 +785,13 @@ async def _grep_revset(self, pattern): self._grep_pattern = pattern csets = defaultdict(set) - async for line in process.hg('grep', '--all', '-l', pattern): - try: - data = dict(parse_colored_line(line)) - except ValueError: - pass - csets[data['grep.rev']].add(data['grep.filename']) + with HG_SEMAPHORE: + async for line in process.hg('grep', '--all', '-l', pattern): + try: + data = dict(parse_colored_line(line)) + except ValueError: + pass + csets[data['grep.rev']].add(data['grep.filename']) revset = ' or '.join(csets) return f'({revset})' diff --git a/lairucrem/process.py b/lairucrem/process.py --- a/lairucrem/process.py +++ b/lairucrem/process.py @@ -31,6 +31,7 @@ msg = cmd + '\n\n' + msg raise OSError(proc.returncode, msg) + class hg: """Async generator yielding mercurial command outputs. @@ -191,9 +192,10 @@ """Execute an Hg command in plain mode and return overall results.""" env = os.environ.copy() env['HGPLAIN'] = '1' - hgproc = hg(*cmd, env=env) - try: - return ''.join([line async for line in hgproc]) - except asyncio.CancelledError: - await hgproc.kill() - return '' + async with config.PROCESSES_SEMAPHORE: + hgproc = hg(*cmd, env=env) + try: + return ''.join([line async for line in hgproc]) + except asyncio.CancelledError: + await hgproc.kill() + return ''