Skip to content

Commit 2bcaeff

Browse files
Add documentation for different task spawning syntaxes (#616)
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
1 parent f4f6177 commit 2bcaeff

File tree

1 file changed

+148
-0
lines changed

1 file changed

+148
-0
lines changed

docs/src/task-spawning.md

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,3 +318,151 @@ In comparison, the `outer_low_occupancy` snippet should show results like this:
318318
0.109904 seconds (55.03 k allocations: 3.631 MiB)
319319
0.117239 seconds (87.95 k allocations: 5.372 MiB)
320320
```
321+
322+
## Different ways to spawn tasks
323+
324+
Beyond the standard function call syntax `Dagger.@spawn f(args...)`, Dagger also supports several other convenient ways to spawn tasks, mirroring Julia's own syntax variations.
325+
326+
### Broadcast
327+
328+
Tasks can be spawned using Julia's broadcast syntax. This is useful for applying an operation element-wise to collections.
329+
330+
```julia
331+
using Dagger
332+
A = rand(4)
333+
B = rand(4)
334+
335+
# Spawn a task to compute A .+ B
336+
add_task = Dagger.@spawn A .+ B
337+
@assert fetch(add_task) A .+ B
338+
339+
x = randn(100)
340+
abs_task = Dagger.@spawn abs.(x)
341+
@assert fetch(abs_task) == abs.(x)
342+
```
343+
344+
### Do block
345+
346+
Dagger supports spawning tasks using Julia's `do` block syntax, which is often used for functions that take another function as an argument, especially anonymous functions.
347+
348+
```julia
349+
using Dagger
350+
A = rand(4)
351+
352+
# Spawn a task using a do block with sum
353+
sum_do_task = Dagger.@spawn sum(A) do a
354+
a + 1
355+
end
356+
@assert fetch(sum_do_task) sum(a -> a + 1, A)
357+
358+
# Spawn a task with a function that accepts a do block
359+
do_f = f -> f(42)
360+
do_task = Dagger.@spawn do_f() do x
361+
x + 1
362+
end
363+
@assert fetch(do_task) == 43
364+
```
365+
366+
### Anonymous direct call
367+
368+
Tasks can be spawned directly from anonymous function definitions.
369+
370+
```julia
371+
using Dagger
372+
A = rand(4)
373+
374+
# Spawn a task from an anonymous function
375+
anon_task = Dagger.@spawn A -> sum(A)
376+
@assert fetch(anon_task) == sum(A)
377+
378+
# Anonymous function with closed-over arguments
379+
dims = 1
380+
anon_kwargs_task = Dagger.@spawn A -> sum(A; dims=dims)
381+
@assert fetch(anon_kwargs_task) == sum(A; dims=dims)
382+
```
383+
384+
### Getindex
385+
386+
Spawning tasks that retrieve elements from indexable collections, such as arrays, using index notation is supported.
387+
388+
```julia
389+
using Dagger
390+
A = rand(4, 4)
391+
392+
# Spawn a task to get A[1, 2]
393+
getindex_task1 = Dagger.@spawn A[1, 2]
394+
@assert fetch(getindex_task1) == A[1, 2]
395+
396+
# Spawn a task to get A[2] (linear indexing)
397+
getindex_task2 = Dagger.@spawn A[2]
398+
@assert fetch(getindex_task2) == A[2]
399+
400+
# Getindex from a DTask result
401+
B_task = Dagger.@spawn rand(4, 4)
402+
getindex_task_from_dtask = Dagger.@spawn B_task[1, 2]
403+
@assert fetch(getindex_task_from_dtask) == fetch(B_task)[1, 2]
404+
405+
R = Ref(42)
406+
# Spawn a task to get R[]
407+
ref_getindex_task = Dagger.@spawn R[]
408+
@assert fetch(ref_getindex_task) == 42
409+
```
410+
411+
### Setindex!
412+
413+
Similarly, tasks can be spawned to modify elements of mutable collections (such as arrays). The object being modified must be running under Datadeps, or wrapped with `Dagger.@mutable`, to ensure that its contents can be mutated correctly.
414+
415+
```julia
416+
using Dagger
417+
A = Dagger.@mutable rand(4, 4)
418+
419+
# Spawn a task to set A[1, 2] = 3.0
420+
setindex_task1 = Dagger.@spawn A[1, 2] = 3.0
421+
fetch(setindex_task1) # Wait for the setindex! to complete
422+
@assert fetch(Dagger.@spawn A[1, 2]) == 3.0
423+
424+
# Spawn a task to set A[2] = 4.0 (linear indexing)
425+
setindex_task2 = Dagger.@spawn A[2] = 4.0
426+
fetch(setindex_task2)
427+
@assert fetch(Dagger.@spawn A[2]) == 4.0
428+
429+
R = Dagger.@mutable Ref(42)
430+
# Spawn a task to set R[] = 43
431+
ref_setindex_task = Dagger.@spawn R[] = 43
432+
fetch(ref_setindex_task)
433+
@assert fetch(Dagger.@spawn R[]) == 43
434+
```
435+
436+
### NamedTuple
437+
438+
Tasks can be spawned to conveniently create `NamedTuple`s.
439+
440+
```julia
441+
using Dagger
442+
443+
# Spawn a task to create a NamedTuple
444+
nt_task = Dagger.@spawn (;a=1, b=2)
445+
@assert fetch(nt_task) == (;a=1, b=2)
446+
447+
# Spawn a task to create an empty NamedTuple
448+
empty_nt_task = Dagger.@spawn (;)
449+
@assert fetch(empty_nt_task) == (;)
450+
```
451+
452+
### Getproperty
453+
454+
Tasks can be spawned to access properties of `NamedTuple`s (or other objects supporting `getproperty`).
455+
456+
```julia
457+
using Dagger
458+
nt = (;a=1, b=2)
459+
460+
# Spawn a task to get nt.b
461+
getprop_task = Dagger.@spawn nt.b
462+
@assert fetch(getprop_task) == nt.b
463+
464+
# Getproperty from a DTask result
465+
nt2_task = Dagger.@spawn (;a=1, b=3)
466+
getprop_task_from_dtask = Dagger.@spawn nt2_task.b
467+
@assert fetch(getprop_task_from_dtask) == fetch(nt2_task).b
468+
```

0 commit comments

Comments
 (0)