-
Notifications
You must be signed in to change notification settings - Fork 697
Initial PoC of Custom Actor Executor support #2388
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Great PoC!
Can we try out marking our |
This is super interesting I'm eager to see what you come up with. It would be ideal if swift had a way to express that everything in this closure will get executed on a specific executor unless |
358dc1a
to
ca0be2f
Compare
0b2211e
to
6479d17
Compare
6479d17
to
5ba3362
Compare
public var executor: any SerialExecutor { | ||
NIODefaultSerialEventLoopExecutor(self) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am wondering if we really should default to this or are better off with a fatalError
. We are making sure our ELs implement this sensible but if somebody created their own EL and we use the default I am a bit concerned that users will just run into crashes for which we could provide a better fatalError
message.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm inclined to want to leave it. The current behaviour will work in the vast majority of cases, and the crashes will be correctness issues anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah probably it's okay since all our ELs do the right thing and there aren't many other ELs out there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems okey to leave this IMHO 👍
Applied your nit. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good 👍 Too bad we couldn't put it onto EL right away but this is okey
Sources/NIOCore/ActorExecutor.swift
Outdated
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#if swift(>=5.9) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just circling back here. If we want there is a way to create a custom serial executor without warnings on 5.9 and blow like this
#if swift(<5.9)
final class MyExecutor: SerialExecutor {
func enqueue(_ job: UnownedJob) {
job._runSynchronously(on: self.asUnownedSerialExecutor())
}
func asUnownedSerialExecutor() -> UnownedSerialExecutor {
UnownedSerialExecutor(ordinary: self)
}
}
#else
@available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *)
final class MyExecutor: SerialExecutor {
@available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *)
func enqueue(_ job: __owned ExecutorJob) {
job.runSynchronously(on: asUnownedSerialExecutor())
}
func asUnownedSerialExecutor() -> UnownedSerialExecutor {
UnownedSerialExecutor(ordinary: self)
}
}
#endif
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks Franz. It's a good suggestion but I'm inclined not to do it: using both _runSynchronously
and __owned
makes me really quite nervous about the stability of that code. @weissi are you happy with having this API on 5.9 only?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm happy with having APIs that are available everywhere from a certain Swift version. But it should be #if compiler
not #if swift
Motivation Swift Concurrency supports having actors opt in to executing within a "custom executor". This requires being able to be strictly serial, a constraint that NIO's EventLoops natively meet. It is useful to have actors be able to express a "tie" to an EventLoop in order to efficiently access objects that are tied to specific ELs. Modifications - Extend EventLoop to expose an executor property - Provide a simple best-effort default using NIODefaultSerialEventLoopExecutor - Expose NIOSerialEventLoopExecutor protocol that makes it easy for adopters to get a better implementation - Crash if EmbeddedEventLoop is used - Add tests Result Adopters can use ELs as serial executors
1423ad8
to
2478733
Compare
This PR tracks an example of custom actor executor support, as well as updating our AsyncAwait example to clearly annotate (via
precondition[Not]OnEventLoop
) whether the code in question is executing on the event loop or not.The initial conclusion here is that this demonstrates the strengths and limitations of custom actor executors for the NIO model. Actors running on an event loop executor clearly run on the event loop, such that the NIO fast-path successfully fires. However, free functions and non-actor types do not inherit this execution context, which limits the utility of our existing async sequences (which are not actors and cannot be EL bound).