Skip to content

Launch tasks from other tasks#471

Merged
mrocklin merged 1 commit into
dask:masterfrom
mrocklin:launch-tasks-from-tasks
Sep 2, 2016
Merged

Launch tasks from other tasks#471
mrocklin merged 1 commit into
dask:masterfrom
mrocklin:launch-tasks-from-tasks

Conversation

@mrocklin

@mrocklin mrocklin commented Aug 30, 2016

Copy link
Copy Markdown
Member

This allows the spawning of tasks from other tasks. We don't add any new scheduling functionality. Instead we make it more convenient to start a client from a task.

In [1]: from distributed import Executor, local_executor

In [2]: e = Executor()

In [3]: def fib(n):
   ...:     if n < 2:
   ...:         return n
   ...:     else:
   ...:         with local_executor() as ee:
   ...:             a, b = ee.submit(fib, n - 1), ee.submit(fib, n - 2)
   ...:             a, b = ee.gather([a, b])
   ...:             return a + b
   ...:         

In [4]: future = e.submit(fib, 100)

In [5]: future
Out[5]: <Future: status: finished, type: int, key: fib-7890e9f06d5f4e0a8fc7ec5c77590ace>

In [6]: future.result()
Out[6]: 354224848179261915075

See associated doc page for more information.

@mrocklin

mrocklin commented Aug 30, 2016

Copy link
Copy Markdown
Member Author

Supercedes #432

@mrocklin
mrocklin force-pushed the launch-tasks-from-tasks branch 2 times, most recently from 7ef09bf to 2a9f855 Compare August 30, 2016 20:21
@mrocklin

Copy link
Copy Markdown
Member Author

There are two ways in which this can deadlock.

  1. All cores in the cluster are waiting on these tasks
  2. All threads in an individual worker are waiting on these tasks while additional tasks are already in the thread-pool-executor's work queue.

The first case is unfortunate, but somewhat controllable and unlikely.

The second case can happen more easily and is harder to control for. Because we're not using coroutines/generator functions we don't have an easy way to jump out of the task and free up the thread. I think our only option here is to add another thread to the ThreadPoolExecutor. This can be done dynamically by changing private variables however the standard concurrent.futures.ThreadPoolExecutor can't scale back down, so adding more space like this is a somewhat irreversible operation. That is unless of course we want to reimplement the ThreadPoolExecutor, which is fairly doable.

@mrocklin

Copy link
Copy Markdown
Member Author

I've resolved the more serious of the deadlocks by allowing tasks that call get_executor() to leave the common thread pool, making space for additional work. This required forking the concurrent.futures.ThreadPoolExecutor.

@mrocklin
mrocklin force-pushed the launch-tasks-from-tasks branch from 7910412 to b8fb0cf Compare August 31, 2016 18:34
@mrocklin

Copy link
Copy Markdown
Member Author

OK, now scatter dumps data directly to the local worker's data dict, bypassing the scheduler.

Additionally I've removed the first deadlock by temporarily increasing the number of slots on any worker that is running a client.

@mrocklin mrocklin mentioned this pull request Sep 1, 2016
@mrocklin
mrocklin force-pushed the launch-tasks-from-tasks branch from 747e536 to 8662ee8 Compare September 1, 2016 23:32
@mrocklin

mrocklin commented Sep 1, 2016

Copy link
Copy Markdown
Member Author

I'm now pretty happy with this. Merging on passed tests

Modified ThreadPoolExecutor to support threads leaving the thread pool

This includes a global `secede` method that a submitted function can call to
have its thread leave the ThreadPoolExecutor's thread pool.  This allows the
thread pool to allocate another thread if necessary and so is useful when a
function realises that it is going to be a long-running job that doesn't want
to take up space.  When the function finishes its thread will terminate
gracefully.

use threadpoolexecutor in worker

Add new WorkerExecutor class

This is the client that a Worker gets internally.  Currently it is
exactly the same, except that `_scatter` dumps to the local worker's
data.

Remove deadlock from long-running tasks

Previously when tasks that created clients ran, they might a slot on the
scheduler for a long time, potentially causing deadlocks.  Now we
increase the number of slots for that worker whenever a task spins up a
client, removing the deadlock but opening ourselves up to
over-saturation.

update docs

add WorkerExecutor._gather method

add docstrings

add PSF license
@mrocklin
mrocklin force-pushed the launch-tasks-from-tasks branch from 8662ee8 to 6de0bbc Compare September 1, 2016 23:42
@mrocklin
mrocklin merged commit 038cdcf into dask:master Sep 2, 2016
@mrocklin
mrocklin deleted the launch-tasks-from-tasks branch September 2, 2016 00:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant