|
294 | 294 | { |
295 | 295 | "data": { |
296 | 296 | "text/plain": [ |
297 | | - "<__main__._t at 0x7efe2eb5ef90>" |
| 297 | + "<__main__._t at 0x7f756accd110>" |
298 | 298 | ] |
299 | 299 | }, |
300 | 300 | "execution_count": null, |
|
1668 | 1668 | { |
1669 | 1669 | "data": { |
1670 | 1670 | "text/plain": [ |
1671 | | - "['a', 'e', 'b', 'h', 'c', 'd', 'g', 'f']" |
| 1671 | + "['c', 'a', 'f', 'e', 'g', 'h', 'd', 'b']" |
1672 | 1672 | ] |
1673 | 1673 | }, |
1674 | 1674 | "execution_count": null, |
|
3570 | 3570 | " except Exception as e: self.on_exc(e)" |
3571 | 3571 | ] |
3572 | 3572 | }, |
| 3573 | + { |
| 3574 | + "cell_type": "code", |
| 3575 | + "execution_count": null, |
| 3576 | + "metadata": {}, |
| 3577 | + "outputs": [], |
| 3578 | + "source": [ |
| 3579 | + "#export\n", |
| 3580 | + "class ThreadPoolExecutor(concurrent.futures.ThreadPoolExecutor):\n", |
| 3581 | + " \"Same as Python's ThreadPoolExecutor, except can pass `max_workers==0` for serial execution\"\n", |
| 3582 | + " def __init__(self, max_workers=defaults.cpus, on_exc=print, pause=0, **kwargs):\n", |
| 3583 | + " if max_workers is None: max_workers=defaults.cpus\n", |
| 3584 | + " store_attr()\n", |
| 3585 | + " self.not_parallel = max_workers==0\n", |
| 3586 | + " if self.not_parallel: max_workers=1\n", |
| 3587 | + " super().__init__(max_workers, **kwargs)\n", |
| 3588 | + "\n", |
| 3589 | + " def map(self, f, items, timeout=None, chunksize=1, *args, **kwargs):\n", |
| 3590 | + " self.lock = Manager().Lock()\n", |
| 3591 | + " g = partial(f, *args, **kwargs)\n", |
| 3592 | + " if self.not_parallel: return map(g, items)\n", |
| 3593 | + " _g = partial(_call, self.lock, self.pause, self.max_workers, g)\n", |
| 3594 | + " try: return super().map(_g, items, timeout=timeout, chunksize=chunksize)\n", |
| 3595 | + " except Exception as e: self.on_exc(e)" |
| 3596 | + ] |
| 3597 | + }, |
3573 | 3598 | { |
3574 | 3599 | "cell_type": "code", |
3575 | 3600 | "execution_count": null, |
|
3580 | 3605 | "text/markdown": [ |
3581 | 3606 | "<h4 id=\"ProcessPoolExecutor\" class=\"doc_header\"><code>class</code> <code>ProcessPoolExecutor</code><a href=\"\" class=\"source_link\" style=\"float:right\">[source]</a></h4>\n", |
3582 | 3607 | "\n", |
3583 | | - "> <code>ProcessPoolExecutor</code>(**`max_workers`**=*`64`*, **`on_exc`**=*`print`*, **`pause`**=*`0`*, **`mp_context`**=*`None`*, **`initializer`**=*`None`*, **`initargs`**=*`()`*) :: [`ProcessPoolExecutor`](/utils.html#ProcessPoolExecutor)\n", |
| 3608 | + "> <code>ProcessPoolExecutor</code>(**`max_workers`**=*`64`*, **`on_exc`**=*`print`*, **`pause`**=*`0`*, **\\*\\*`kwargs`**) :: [`ProcessPoolExecutor`](/utils.html#ProcessPoolExecutor)\n", |
3584 | 3609 | "\n", |
3585 | 3610 | "Same as Python's ProcessPoolExecutor, except can pass `max_workers==0` for serial execution" |
3586 | 3611 | ], |
|
3615 | 3640 | "source": [ |
3616 | 3641 | "#export \n", |
3617 | 3642 | "def parallel(f, items, *args, n_workers=defaults.cpus, total=None, progress=None, pause=0,\n", |
3618 | | - " timeout=None, chunksize=1, **kwargs):\n", |
| 3643 | + " threadpool=False, timeout=None, chunksize=1, **kwargs):\n", |
3619 | 3644 | " \"Applies `func` in parallel to `items`, using `n_workers`\"\n", |
3620 | 3645 | " if progress is None: progress = progress_bar is not None\n", |
3621 | | - " with ProcessPoolExecutor(n_workers, pause=pause) as ex:\n", |
| 3646 | + " pool = ThreadPoolExecutor if threadpool else ProcessPoolExecutor\n", |
| 3647 | + " with pool(n_workers, pause=pause) as ex:\n", |
3622 | 3648 | " r = ex.map(f,items, *args, timeout=timeout, chunksize=chunksize, **kwargs)\n", |
3623 | 3649 | " if progress:\n", |
3624 | 3650 | " if total is None: total = len(items)\n", |
|
3651 | 3677 | "metadata": {}, |
3652 | 3678 | "output_type": "display_data" |
3653 | 3679 | }, |
3654 | | - { |
3655 | | - "data": { |
3656 | | - "text/html": [], |
3657 | | - "text/plain": [ |
3658 | | - "<IPython.core.display.HTML object>" |
3659 | | - ] |
3660 | | - }, |
3661 | | - "metadata": {}, |
3662 | | - "output_type": "display_data" |
3663 | | - }, |
3664 | 3680 | { |
3665 | 3681 | "data": { |
3666 | 3682 | "text/html": [], |
|
3678 | 3694 | " return x+a\n", |
3679 | 3695 | "\n", |
3680 | 3696 | "inp,exp = range(50),range(1,51)\n", |
3681 | | - "test_eq(parallel(add_one, inp, n_workers=2), exp)\n", |
| 3697 | + "test_eq(parallel(add_one, inp, n_workers=2, progress=False), exp)\n", |
| 3698 | + "test_eq(parallel(add_one, inp, threadpool=True, n_workers=2, progress=False), exp)\n", |
3682 | 3699 | "test_eq(parallel(add_one, inp, n_workers=0), exp)\n", |
3683 | 3700 | "test_eq(parallel(add_one, inp, n_workers=1, a=2), range(2,52))\n", |
3684 | 3701 | "test_eq(parallel(add_one, inp, n_workers=0, a=2), range(2,52))" |
|
3688 | 3705 | "cell_type": "markdown", |
3689 | 3706 | "metadata": {}, |
3690 | 3707 | "source": [ |
3691 | | - "Use the `pause` parameter to ensure a pause of `pause` seconds between processes starting. This is in case there are race conditions in starting some process, or to stagger the time each process starts, for example when making many requests to a webserver." |
| 3708 | + "Use the `pause` parameter to ensure a pause of `pause` seconds between processes starting. This is in case there are race conditions in starting some process, or to stagger the time each process starts, for example when making many requests to a webserver. Set `threadpool=True` to use `ThreadPoolExecutor` instead of `ProcessPoolExecutor`." |
3692 | 3709 | ] |
3693 | 3710 | }, |
3694 | 3711 | { |
|
0 commit comments