-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[Concurrency] YieldingContinuation #36730
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
[Concurrency] YieldingContinuation #36730
Conversation
@swift-ci please smoke test macOS |
@swift-ci please test |
@swift-ci please smoke test macOS |
3 similar comments
@swift-ci please smoke test macOS |
@swift-ci please smoke test macOS |
@swift-ci please smoke test macOS |
Build failed |
@swift-ci please smoke test macOS |
@swift-ci please clean smoke test macOS |
@swift-ci please test macOS |
@swift-ci please smoke test macOS |
Build failed |
@swift-ci please smoke test macOS |
@swift-ci please test macOS |
Build failed |
@swift-ci please smoke test macOS |
@swift-ci please test macOS |
Build failed |
@swift-ci please smoke test |
…re than once via a yielding family of functions and awaiting production via next
3fdab27
to
46ff414
Compare
@swift-ci please smoke test |
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.
Mostly LGTM. I'll leave the naming question to Evolution.
@usableFromInline | ||
internal final class Storage: UnsafeSendable { | ||
@usableFromInline | ||
var continuation: UnsafeContinuation<Element, Error>? |
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.
You could reduce metadata explosion by hoisting this effectively nongeneric storage class out of the generic outer type, so we only need one class object for all instances.
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.
hmm good idea; and then store the continuation as a raw crunchy continuation?
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.
extracted!
/// Await a resume from a call to a yielding function. | ||
/// | ||
/// - Return: The element that was yielded or a error that was thrown. | ||
public func next() async throws -> Element { |
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.
The signature of next()
here is wrong for any Failure type other than Error
, so it might be least-bad to move this into an extension where Failure == Error
, to leave room for a generic throws T
API here if we ever get typed throws.
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.
that poses a problem; then it is invalid to construct ones w/ a specific error type - should we enforce that initializer into that extension as well?
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.
converted to the specific variant.
…o acqrel atomics, and change the error type to be enforced to Error existentials for next.
@swift-ci please smoke test |
@swift-ci please smoke test macOS |
let failure2 = SomeError() | ||
let t = detach { | ||
do { | ||
let value1 = try await continuation.next() |
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.
We should have an expectUnreachable
after this line (and below, in this test and 2x in the next test)
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.
fair, will change
@swift-ci Please build toolchain macOS platform |
@swift-ci please smoke test |
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.
Okay, my non-evolution concerns have been addressed
@swift-ci please smoke test linux |
After the merge of swiftlang#36730, both VS2017 and VS2019 CI machines started failing. There are many crashes related to concurrency. Disable the tests in Windows to not loose signal on the CI machines. See https://bugs.swift.org/browse/SR-14333 for more disabled tests and discussion.
This implements a YieldingContinuation type suitable for emitting values more than once via a yielding family of functions and awaiting production via next
This is a type suitable for usage points that need to resume an awaiting function more than once. This can be used to implement AsyncIteratorProtocol adopters for AsyncSequence that are sourced from state that is external from the control of the iterator. Callbacks or delegation can be passed this continuation type (unlike the Unsafe and Checked variants usable for singular callbacks) as an escaping/sendable concept. This means that the continuation can escape into closures that get called more than once. Yielding will return a boolean state identifying that the continuation was resumed or not. Ignoring this will result in a dropping style behavior (e.g. if no one is awaiting a value the value will be dropped). Implementors of async iterators need to choose if the values are distinct and need to be buffered for use before the next awaiting call is invoked.