parallel: Remove run_parallel.

This was a broken abstraction that returned to its caller within
multiple forked processes on exceptions, and encouraged ignoring the
error code (as all of its callers did).

Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
This commit is contained in:
Anders Kaseorg 2019-07-27 16:23:13 -07:00 committed by Tim Abbott
parent 0f16df2f13
commit a659542d84
4 changed files with 1 additions and 79 deletions

View File

@ -126,9 +126,7 @@ eslint, and other home grown tools.
You can find the source code [here](https://github.com/zulip/zulip/blob/master/tools/lint). You can find the source code [here](https://github.com/zulip/zulip/blob/master/tools/lint).
In order for our entire lint suite to run in a timely fashion, the `lint` In order for our entire lint suite to run in a timely fashion, the `lint`
script performs several lint checks in parallel by forking out subprocesses. This mechanism script performs several lint checks in parallel by forking out subprocesses.
is still evolving, but you can look at the method `run_parallel` to get the
gist of how it works.
Note that our project does custom regex-based checks on the code, and we Note that our project does custom regex-based checks on the code, and we
also customize how we call pyflakes and pycodestyle (pep8). The code for these also customize how we call pyflakes and pycodestyle (pep8). The code for these

View File

@ -32,7 +32,6 @@ omit =
zerver/lib/test_runner.py zerver/lib/test_runner.py
# Has its own independent test suite # Has its own independent test suite
zerver/openapi/python_examples.py zerver/openapi/python_examples.py
zerver/lib/parallel.py
# Debugging tools that don't lend themselves well to unit tests # Debugging tools that don't lend themselves well to unit tests
zerver/lib/debug.py zerver/lib/debug.py
# Part of provisioning/populate_db # Part of provisioning/populate_db

View File

@ -91,7 +91,6 @@ not_yet_fully_covered = [
'zerver/lib/logging_util.py', 'zerver/lib/logging_util.py',
'zerver/lib/migrate.py', 'zerver/lib/migrate.py',
'zerver/lib/outgoing_webhook.py', 'zerver/lib/outgoing_webhook.py',
'zerver/lib/parallel.py',
'zerver/lib/profile.py', 'zerver/lib/profile.py',
'zerver/lib/queue.py', 'zerver/lib/queue.py',
'zerver/lib/sqlalchemy_utils.py', 'zerver/lib/sqlalchemy_utils.py',

View File

@ -1,74 +0,0 @@
import errno
import os
import pty
import sys
from typing import Callable, Dict, Iterable, Iterator, Tuple, TypeVar
JobData = TypeVar('JobData')
def run_parallel(job: Callable[[JobData], int],
data: Iterable[JobData],
threads: int=6) -> Iterator[Tuple[int, JobData]]:
pids: Dict[int, JobData] = {}
def wait_for_one() -> Tuple[int, JobData]:
while True:
try:
(pid, status) = os.wait()
return status, pids.pop(pid)
except KeyError:
pass
for item in data:
pid = os.fork()
if pid == 0:
sys.stdin.close()
try:
os.close(pty.STDIN_FILENO)
except OSError as e:
if e.errno != errno.EBADF:
raise
sys.stdin = open("/dev/null")
os._exit(job(item))
pids[pid] = item
threads = threads - 1
if threads == 0:
(status, item) = wait_for_one()
threads += 1
yield (status, item)
if status != 0:
# Stop if any error occurred
break
while True:
try:
(status, item) = wait_for_one()
yield (status, item)
except OSError as e:
if e.errno == errno.ECHILD:
break
else:
raise
if __name__ == "__main__":
# run some unit tests
import time
jobs = [10, 19, 18, 6, 14, 12, 8, 2, 1, 13, 3, 17, 9, 11, 5, 16, 7, 15, 4]
expected_output = [6, 10, 12, 2, 1, 14, 8, 3, 18, 19, 5, 9, 13, 11, 4, 7, 17, 16, 15]
def wait_and_print(x: int) -> int:
time.sleep(x * 0.1)
return 0
output = []
for (status, job) in run_parallel(wait_and_print, jobs):
output.append(job)
if output == expected_output:
print("Successfully passed test!")
else:
print("Failed test!")
print(jobs)
print(expected_output)
print(output)