@@ -15,16 +15,16 @@ considered valid.
15
15
16
16
Let's take the example of a webcam handle generated by VideoIO.jl. This handle
17
17
is a C pointer, and thus has process scope. We can open the handle on a given
18
- process, and set the scope of the resulting data to a ` ProcessScope() ` , which
19
- defaults to the current Julia process :
18
+ process, and set the scope of the resulting data to be locked to the current
19
+ process with ` Dagger.scope ` to construct a ` ProcessScope ` :
20
20
21
21
``` julia
22
- using VideoIO
22
+ using VideoIO, Distributed
23
23
24
24
function get_handle ()
25
25
handle = VideoIO. opencamera ()
26
26
proc = Dagger. thunk_processor ()
27
- scope = ProcessScope ()
27
+ scope = Dagger . scope (worker = myid ()) # constructs a `ProcessScope`
28
28
return Dagger. tochunk (handle, proc, scope)
29
29
end
30
30
@@ -41,7 +41,7 @@ cam_frame = Dagger.@spawn read(cam_handle)
41
41
42
42
The ` cam_frame ` task is executed within any processor on the same process that
43
43
the ` cam_handle ` task was executed on. Of course, the resulting camera frame is
44
- * not* scoped to anywhere specific (denoted as ` AnyScope() ` ), and thus
44
+ * not* scoped to anywhere specific (denoted as ` AnyScope ` ), and thus
45
45
computations on it may execute anywhere.
46
46
47
47
You may also encounter situations where you want to use a callable struct (such
@@ -53,13 +53,15 @@ using Flux
53
53
m = Chain (... )
54
54
# If `m` is only safe to transfer to and execute on this process,
55
55
# we can set a `ProcessScope` on it:
56
- result = Dagger. @spawn scope= ProcessScope ( ) m (rand (8 ,8 ))
56
+ result = Dagger. @spawn scope= Dagger . scope (worker = myid () ) m (rand (8 ,8 ))
57
57
```
58
58
59
59
Setting a scope on the function treats it as a regular piece of data (like the
60
60
arguments to the function), so it participates in the scoping rules described
61
61
in the following sections all the same.
62
62
63
+ [ ` Dagger.scope ` ] ( @ref )
64
+
63
65
Now, let's try out some other kinds of scopes, starting with ` NodeScope ` . This
64
66
scope encompasses the server that one or more Julia processes may be running
65
67
on. Say we want to use memory mapping (mmap) to more efficiently send arrays
@@ -75,6 +77,7 @@ function generate()
75
77
arr = Mmap. mmap (path, Matrix{Int}, (64 ,64 ))
76
78
fill! (arr, 1 )
77
79
Mmap. sync! (arr)
80
+ # Note: Dagger.scope() does not yet support node scopes
78
81
Dagger. tochunk (path, Dagger. thunk_processor (), NodeScope ())
79
82
end
80
83
@@ -87,14 +90,14 @@ a = Dagger.@spawn generate()
87
90
@assert fetch (Dagger. @spawn consume (a)) == 64 * 64
88
91
```
89
92
90
- Whatever server ` a ` executed on, ` b ` will also execute on!
93
+ Whatever server ` a ` executed on, ` b ` will also execute on it !
91
94
92
95
Finally, we come to the "lowest" scope on the scope hierarchy, the
93
96
` ExactScope ` . This scope specifies one exact processor as the bounding scope,
94
- and is typically useful in certain limited cases. We won't provide an example
95
- here, because you don 't usually need to ever use this scope, but if you already
96
- understand the ` NodeScope ` and ` ProcessScope ` , the ` ExactScope ` should be easy
97
- to figure out.
97
+ and is typically useful in certain limited cases (such as data existing only on
98
+ a specific GPU). We won 't provide an example here, because you don't usually
99
+ need to ever use this scope, but if you already understand the ` NodeScope ` and
100
+ ` ProcessScope ` , the ` ExactScope ` should be easy to figure out.
98
101
99
102
## Union Scopes
100
103
0 commit comments