dispatch_apply.3 3.7 KB

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