You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: proposals/0417-task-executor-preference.md
-57Lines changed: 0 additions & 57 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -642,63 +642,6 @@ func function() async {
642
642
}
643
643
```
644
644
645
-
#### What about the Main Actor?
646
-
647
-
While the `MainActor` is not really special under this model, and behaves just asany other actor_with_ a specific executor requirement.
648
-
649
-
It is worth reminding that using the main actor's executor as a preferred executor would have the same effect as with any other executor. While usually using the main actor as preferred executor is not recommended. After all, this is why the original proposal was made to make nonisolated async functions hop *off* from their calling context, in order to free the main actor to interleave other work while other asynchronous work is happening.
650
-
651
-
In some situations, where the called asynchronous function may be expected to actually never suspend directly but only sometimes call another actor, and otherwise just return immediately without ever suspending. This may be used as fine optimization to tune around specific well known calls.
652
-
653
-
### Task executor preference and `AsyncSequence`s
654
-
655
-
One use-case worth calling out is AsyncSequences, especially when used from actors.
656
-
657
-
The following snippet illustrates a common performance pitfall today:
658
-
659
-
```swift
660
-
actor Looper {
661
-
funcconsumeSequence() async {
662
-
forawait value ingetAsyncSequence() {
663
-
// 1. hop-to global pool: await next()
664
-
// 2. hop-to actor: execute for-loop body
665
-
print("got: \(value)")
666
-
}
667
-
}
668
-
}
669
-
```
670
-
671
-
Because an async sequence's iterator has a nonisolated `next()` method (declared like this `funcnext() async ->Element?`),
672
-
under the current execution semantics, the execution will _always_ hop to the global concurrent executor to execute the `next()` method,
673
-
and only then let it run, potentially produce a value without even suspending (!), and hop back to the actorto process the body of the for-loop.
674
-
675
-
This is unfortunate and can cause a lot of back-and forth hopping that may not necessarily be desirable. Especially with async sequences which employ
676
-
some form of buffering, such that e.g. the sequence has a number of elements "ready" and will return them immediately without having to suspend or synchronize with other `isolated` code.
677
-
678
-
With the use of task executor preference, we are able to circumvent the hops to the global concurrent executor, by preferring the actor's own executor, like this:
679
-
680
-
```swift
681
-
actor Looper {
682
-
funcconsumeSequence() async {
683
-
withTaskExecutor(self) {
684
-
forawait value ingetAsyncSequence() {
685
-
// 1.a. 'next()' can execute on Looper's executor
686
-
// 1.b. if next() needs to call some other isolated code, we would hop there
687
-
// but only when necessary.
688
-
// 2.a. Following the fast path where next() executed directly on Looper.executor,
689
-
// the "hop back to actor" is efficient because it is a hop to the same executor which is a no-op.
690
-
// 2.b. Following the slow path where next() had to call some `isolated` code,
691
-
// the hop back to the Looper is the same as it would be normally.
692
-
print("got: \(value)")
693
-
}
694
-
}
695
-
}
696
-
}
697
-
```
698
-
699
-
Async sequences are expected to undergo further evolution in order to express isolation more efficiently in the actorcase.
700
-
Task executors are expected to fit well into this model, and offer an additional layer of "fine tuning" of developers encounter the need to do so.
701
-
702
645
## Prior-Art
703
646
704
647
It is worth comparing with other concurrency runtimes with similar concepts to make sure if there are some common ideas or something different other projects have researched.
0 commit comments