1 .\" Copyright (c) 2008-2017 Apple Inc. All rights reserved.
7 .Nd schedule blocks for iterative execution
9 .Fd #include <dispatch/dispatch.h>
12 .Fa "size_t iterations" "dispatch_queue_t queue" "void (^block)(size_t)"
16 .Fa "size_t iterations" "dispatch_queue_t queue" "void *context" "void (*function)(void *, size_t)"
21 function provides data-level concurrency through a "for (;;)" loop like primitive:
23 size_t iterations = 10;
25 // 'idx' is zero indexed, just like:
26 // for (idx = 0; idx < iterations; idx++)
28 dispatch_apply(iterations, DISPATCH_APPLY_AUTO, ^(size_t idx) {
29 printf("%zu\\n", idx);
33 Although any queue can be used, it is strongly recommended to use
34 .Vt DISPATCH_APPLY_AUTO
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.
45 Like a "for (;;)" loop, the
47 function is synchronous.
48 If asynchronous behavior is desired, wrap the call to
52 against another queue.
54 Sometimes, when the block passed to
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):
63 dispatch_apply(count / STRIDE, DISPATCH_APPLY_AUTO, ^(size_t idx) {
64 size_t j = idx * STRIDE;
65 size_t j_stop = j + STRIDE;
67 printf("%zu\\n", j++);
72 for (i = count - (count % STRIDE); i < count; i++) {
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).
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).
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
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
102 when parallel execution is important.
106 function is a wrapper around
107 .Fn dispatch_apply_f .
113 is expected to be either independent or dependent
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
121 .Xr dispatch_async 3 ,
122 .Xr dispatch_queue_create 3