]>
Commit | Line | Data |
---|---|---|
6b746eb4 | 1 | .\" Copyright (c) 2008-2017 Apple Inc. All rights reserved. |
0ab74447 A |
2 | .Dd May 1, 2009 |
3 | .Dt dispatch_apply 3 | |
4 | .Os Darwin | |
5 | .Sh NAME | |
6 | .Nm dispatch_apply | |
7 | .Nd schedule blocks for iterative execution | |
8 | .Sh SYNOPSIS | |
9 | .Fd #include <dispatch/dispatch.h> | |
10 | .Ft void | |
11 | .Fo dispatch_apply | |
12 | .Fa "size_t iterations" "dispatch_queue_t queue" "void (^block)(size_t)" | |
13 | .Fc | |
14 | .Ft void | |
15 | .Fo dispatch_apply_f | |
16 | .Fa "size_t iterations" "dispatch_queue_t queue" "void *context" "void (*function)(void *, size_t)" | |
17 | .Fc | |
18 | .Sh DESCRIPTION | |
19 | The | |
20 | .Fn dispatch_apply | |
21 | function provides data-level concurrency through a "for (;;)" loop like primitive: | |
22 | .Bd -literal | |
0ab74447 A |
23 | size_t iterations = 10; |
24 | ||
25 | // 'idx' is zero indexed, just like: | |
26 | // for (idx = 0; idx < iterations; idx++) | |
27 | ||
6b746eb4 | 28 | dispatch_apply(iterations, DISPATCH_APPLY_AUTO, ^(size_t idx) { |
0ab74447 A |
29 | printf("%zu\\n", idx); |
30 | }); | |
31 | .Ed | |
32 | .Pp | |
6b746eb4 A |
33 | Although any queue can be used, it is strongly recommended to use |
34 | .Vt DISPATCH_APPLY_AUTO | |
35 | as the | |
36 | .Vt queue | |
37 | argument to both | |
38 | .Fn dispatch_apply | |
39 | and | |
40 | .Fn dispatch_apply_f , | |
41 | as shown in the example above, since this allows the system to automatically use worker threads | |
42 | that match the configuration of the current thread as closely as possible. | |
43 | No assumptions should be made about which global concurrent queue will be used. | |
44 | .Pp | |
0ab74447 A |
45 | Like a "for (;;)" loop, the |
46 | .Fn dispatch_apply | |
47 | function is synchronous. | |
6b746eb4 | 48 | If asynchronous behavior is desired, wrap the call to |
0ab74447 A |
49 | .Fn dispatch_apply |
50 | with a call to | |
51 | .Fn dispatch_async | |
52 | against another queue. | |
53 | .Pp | |
54 | Sometimes, when the block passed to | |
55 | .Fn dispatch_apply | |
56 | is simple, the use of striding can tune performance. | |
57 | Calculating the optimal stride is best left to experimentation. | |
58 | Start with a stride of one and work upwards until the desired performance is | |
59 | achieved (perhaps using a power of two search): | |
60 | .Bd -literal | |
e85f4437 | 61 | #define STRIDE 3 |
0ab74447 | 62 | |
6b746eb4 | 63 | dispatch_apply(count / STRIDE, DISPATCH_APPLY_AUTO, ^(size_t idx) { |
0ab74447 A |
64 | size_t j = idx * STRIDE; |
65 | size_t j_stop = j + STRIDE; | |
66 | do { | |
67 | printf("%zu\\n", j++); | |
68 | } while (j < j_stop); | |
69 | }); | |
70 | ||
71 | size_t i; | |
72 | for (i = count - (count % STRIDE); i < count; i++) { | |
73 | printf("%zu\\n", i); | |
74 | } | |
75 | .Ed | |
e85f4437 A |
76 | .Sh IMPLIED REFERENCES |
77 | Synchronous functions within the dispatch framework hold an implied reference | |
78 | on the target queue. In other words, the synchronous function borrows the | |
79 | reference of the calling function (this is valid because the calling function | |
80 | is blocked waiting for the result of the synchronous function, and therefore | |
81 | cannot modify the reference count of the target queue until after the | |
82 | synchronous function has returned). | |
83 | .Pp | |
84 | This is in contrast to asynchronous functions which must retain both the block | |
85 | and target queue for the duration of the asynchronous operation (as the calling | |
86 | function may immediately release its interest in these objects). | |
0ab74447 | 87 | .Sh FUNDAMENTALS |
0ab74447 | 88 | .Fn dispatch_apply |
6b746eb4 A |
89 | and |
90 | .Fn dispatch_apply_f | |
91 | attempt to quickly create enough worker threads to efficiently iterate work in parallel. | |
92 | By contrast, a loop that passes work items individually to | |
0ab74447 | 93 | .Fn dispatch_async |
6b746eb4 A |
94 | or |
95 | .Fn dispatch_async_f | |
96 | will incur more overhead and does not express the desired parallel execution semantics to | |
97 | the system, so may not create an optimal number of worker threads for a parallel workload. | |
98 | For this reason, prefer to use | |
99 | .Fn dispatch_apply | |
100 | or | |
101 | .Fn dispatch_apply_f | |
102 | when parallel execution is important. | |
0ab74447 A |
103 | .Pp |
104 | The | |
105 | .Fn dispatch_apply | |
106 | function is a wrapper around | |
107 | .Fn dispatch_apply_f . | |
e85f4437 A |
108 | .Sh CAVEATS |
109 | Unlike | |
110 | .Fn dispatch_async , | |
111 | a block submitted to | |
112 | .Fn dispatch_apply | |
113 | is expected to be either independent or dependent | |
114 | .Em only | |
115 | on work already performed in lower-indexed invocations of the block. If | |
116 | the block's index dependency is non-linear, it is recommended to | |
117 | use a for-loop around invocations of | |
118 | .Fn dispatch_async . | |
0ab74447 | 119 | .Sh SEE ALSO |
e85f4437 | 120 | .Xr dispatch 3 , |
0ab74447 | 121 | .Xr dispatch_async 3 , |
6b746eb4 | 122 | .Xr dispatch_queue_create 3 |