ExecutorProtocol
public protocol ExecutorProtocol : AnyObject
A protocol that defines objects that execute futures.
Executors provide the context in which futures execute. This context may
be the current or a background thread, a Dispatch queue, a run loop, etc.
Executors typically enqueue submitted futures in a ready to run
queue
and immediately return to the caller. This queue is later on consumed by
the executor in its execution context, driving futures to completion by
polling them. The polling algorithm is roughly:
var context = self.makeContext()
while var future = self.readyToRunQueue.pop() {
if future.poll(&context).isReady {
self.drop(future)
} else {
self.pendingFutures.push(future)
}
}
Futures that are ready to run are polled by the executor. If the future
returns that it completed (see Poll
), it is let go by the executor,
which causes the future and associated resources to be released. Otherwise,
it is added into a pending futures
registry. Before returning, the
future registers the context’s waker (see Context
and WakerProtocol
)
to receive a notification when the external event the future is waiting on
fires. As a result of the notification, the future is added back into the
ready to run
queue and the process repeats until the future signifies
completion.
Futures are submitted for execution via the trySubmit(_:)
method of an
executor. Executors guarantee that submitted futures will be executed
asynchronously. In other words, trySubmit(_:)
merely schedules the
future to be executed at some point in the future and returns to the caller
immediately. This is an important invariant that custom implementations
must also maintain, since it removes all concerns about reentrancy.
Executors may deny to receive the future, in which case trySubmit(_:)
returns an appropriate error of type Failure
. This can be the case when
the executor is shutting down or is at capacity and needs to provide
backpressure. Executors that never fail, declare their Failure
type as
Never
.
This protocol makes no guarantees on the safety of concurrent calls to
trySubmit(_:)
. Each executor implementation is free to declare support
for concurrent submissions, documenting the fact accordingly. This ambiguity
is not a problem in practice since you typically use concrete executor types
so you always know the specifics. The built-in QueueExecutor
is an
executor that supports concurrent submissions.
-
The type of error the executor may fail with when submitting futures.
Declaration
Swift
associatedtype Failure : Error
-
The maximum number of futures the executor can track concurrently.
If the executor is unbounded, this property returns
Int.max
; seeisUnbounded
.Declaration
Swift
var capacity: Int { get }
-
trySubmit(_:)
Default implementationSubmits a future to be executed by this executor.
The executor may deny to receive the future, in which case the returned result will contain an appropriate error. Typical cases where submission may fail is when the executor is shutting down or is at capacity and needs to provide backpressure. The latter case is expected to be a transient state which the executor will recover from and submission may be retried.
Default Implementation
Submits a stream to be executed by this executor.
The executor may deny to receive the stream, in which case the returned result will contain an appropriate error. Typical cases where submission may fail is when the executor is shutting down or is at capacity and needs to provide backpressure. The latter case is expected to be a transient state which the executor will recover from and submission may be retried.
Use this method with care as it may trap at runtime. This method is convenience for:
executor.trySubmit(stream.ignoreOutput())
Declaration
Swift
func trySubmit<F>(_ future: F) -> Result<Void, Failure> where F : FutureProtocol, F.Output == Void
-
isUnbounded
Extension methodReturns a boolean denoting whether the executor can accept an unlimited number of futures.
Declaration
Swift
@inlinable public var isUnbounded: Bool { get }
-
submit(_:)
Extension methodSubmits a future to be executed by this executor.
Use this method with care as it may trap at runtime. This method is convenience for:
try! executor.trySubmit(future).get()
Declaration
Swift
@inlinable public func submit<F>(_ future: F) where F : FutureProtocol, F.Output == Void
-
submit(_:)
Extension methodSubmits a stream to be executed by this executor.
Use this method with care as it may trap at runtime. This method is convenience for:
try! executor.trySubmit(stream.ignoreOutput()).get()
Declaration
Swift
@inlinable public func submit<S>(_ stream: S) where S : StreamProtocol, S.Output == Void
-
trySpawn(_:)
Extension methodSubmits a future into the executor and returns a handle that can be used to extract its result or cancel its execution.
The handle is a cancellable future itself and can be safely sent and waited on any thread or submitted into another executor; see
Task
.Declaration
Swift
@inlinable public func trySpawn<F>(_ future: F) -> Result<Task<F.Output>, Failure> where F : FutureProtocol
-
spawn(_:)
Extension methodSubmits a future into the executor and returns a handle that can be used to extract its result or cancel its execution.
The handle is a cancellable future itself and can be safely sent and waited on any thread or submitted into another executor; see
Task
.Use this method with care as it may trap at runtime. This method is convenience for:
try! executor.trySpawn(future).get()
Declaration
Swift
@inlinable public func spawn<F>(_ future: F) -> Task<F.Output> where F : FutureProtocol
-
submit(_:)
Extension methodDeclaration
Swift
@inlinable public func submit<F>(_ future: F) where F : FutureProtocol, F.Output == Result<Void, Never>
-
submit(_:)
Extension methodDeclaration
Swift
@inlinable public func submit<S>(_ stream: S) where S : StreamProtocol, S.Output == Result<Void, Never>