72 lines
2.4 KiB
Python
72 lines
2.4 KiB
Python
import asyncio
|
|
import inspect
|
|
import multiprocessing as mp
|
|
import queue
|
|
import threading
|
|
import traceback
|
|
from multiprocessing.synchronize import Event
|
|
from typing import Any, Awaitable, Callable, List, TypeVar, Union, cast
|
|
|
|
import dill
|
|
|
|
from .map_result import MapResult
|
|
|
|
T = TypeVar("T")
|
|
V = TypeVar("V")
|
|
|
|
|
|
def mapper_function(
|
|
input_queue: Union[mp.Queue, queue.Queue],
|
|
output_queue: Union[mp.Queue, queue.Queue],
|
|
should_stop: Union[Event, threading.Event],
|
|
func: Union[bytes, Callable[[T], V], Callable[[T], Awaitable[V]]],
|
|
) -> None:
|
|
try:
|
|
if isinstance(func, bytes):
|
|
func = cast(Callable[[T], V], dill.loads(func))
|
|
|
|
is_asynchronous = inspect.iscoroutinefunction(func)
|
|
|
|
last_chunk: List[MapResult] = []
|
|
while not should_stop.wait(0.1):
|
|
if not last_chunk:
|
|
try:
|
|
input_chunk = input_queue.get_nowait()
|
|
if is_asynchronous:
|
|
|
|
async def safe(i: int, value: T) -> Any:
|
|
try:
|
|
return MapResult(
|
|
i,
|
|
await cast(Callable[[T], Awaitable[V]], func)(
|
|
value
|
|
),
|
|
)
|
|
except Exception as e:
|
|
return MapResult(i, None, e, traceback.format_exc())
|
|
|
|
async def main() -> List[MapResult]:
|
|
return await asyncio.gather(
|
|
*[safe(i, v) for i, v in input_chunk]
|
|
)
|
|
|
|
last_chunk = asyncio.run(main())
|
|
else:
|
|
for i, value in input_chunk:
|
|
try:
|
|
last_chunk.append(MapResult(i, func(value)))
|
|
except Exception as e:
|
|
last_chunk.append(
|
|
MapResult(i, None, e, traceback.format_exc())
|
|
)
|
|
except queue.Empty:
|
|
pass
|
|
|
|
if last_chunk:
|
|
try:
|
|
output_queue.put_nowait(last_chunk)
|
|
last_chunk = []
|
|
except queue.Full:
|
|
pass
|
|
except (KeyboardInterrupt, BrokenPipeError):
|
|
pass
|