Creates a simple, non-cancelable F[A]
instance that
executes an asynchronous process on evaluation.
Creates a simple, non-cancelable F[A]
instance that
executes an asynchronous process on evaluation.
The given function is being injected with a side-effectful callback for signaling the final result of an asynchronous process.
This operation could be derived from asyncF, because:
F.async(k) <-> F.asyncF(cb => F.delay(k(cb)))
As an example of wrapping an impure async API, here's the implementation of Async.shift:
def shift[F[_]](ec: ExecutionContext)(implicit F: Async[F]): F[Unit] = F.async { cb => // Scheduling an async boundary (logical thread fork) ec.execute(new Runnable { def run(): Unit = { // Signaling successful completion cb(Right(())) } }) }
is a function that should be called with a callback for signaling the result once it is ready
Creates a simple, non-cancelable F[A]
instance that
executes an asynchronous process on evaluation.
Creates a simple, non-cancelable F[A]
instance that
executes an asynchronous process on evaluation.
The given function is being injected with a side-effectful
callback for signaling the final result of an asynchronous
process. And its returned result needs to be a pure F[Unit]
that gets evaluated by the runtime.
Note the simpler async variant async can be derived like this:
F.async(k) <-> F.asyncF(cb => F.delay(k(cb)))
For wrapping impure APIs usually you can use the simpler async,
however asyncF
is useful in cases where impure APIs are
wrapped with the help of pure abstractions, such as
Ref.
For example here's how a simple, "pure Promise" implementation
could be implemented via Ref
(sample is for didactic purposes,
as you have a far better
Deferred available):
import cats.effect.concurrent.Ref type Callback[-A] = Either[Throwable, A] => Unit class PurePromise[F[_], A](ref: Ref[F, Either[List[Callback[A]], A]]) (implicit F: Async[F]) { def get: F[A] = F.asyncF { cb => ref.modify { case current @ Right(result) => (current, F.delay(cb(Right(result)))) case Left(list) => (Left(cb :: list), F.unit) } } def complete(value: A): F[Unit] = F.flatten(ref.modify { case Left(list) => (Right(value), F.delay(list.foreach(_(Right(value))))) case right => (right, F.unit) }) }
N.B. if F[_]
is a cancelable data type (i.e. implementing
Concurrent), then the returned F[Unit]
can be cancelable,
its evaluation hooking into the underlying cancelation mechanism
of F[_]
, so something like this behaves like you'd expect:
def delayed[F[_], A](thunk: => A) (implicit F: Async[F], timer: Timer[F]): F[A] = { timer.sleep(1.second) *> F.delay(cb( try cb(Right(thunk)) catch { case NonFatal(e) => Left(cb(Left(e))) } )) }
The asyncF
operation behaves like Sync.suspend, except
that the result has to be signaled via the provided callback.
As a matter of contract the returned F[Unit]
should not
throw errors. If it does, then the behavior is undefined.
This is because by contract the provided callback should
only be called once. Calling it concurrently, multiple times,
is a contract violation. And if the returned F[Unit]
throws,
then the implementation might have called it already, so it
would be a contract violation to call it without expensive
synchronization.
In case errors are thrown the behavior is implementation specific. The error might get logged to stderr, or via other mechanisms that are implementations specific.
is a function that should be called with a callback for signaling the result once it is ready
A generalized version of bracket which uses ExitCase to distinguish between different exit cases when releasing the acquired resource.
A generalized version of bracket which uses ExitCase to distinguish between different exit cases when releasing the acquired resource.
is an action that "acquires" some expensive resource, that needs to be used and then discarded
is the action that uses the newly allocated resource and that will provide the final result
is the action that's supposed to release the
allocated resource after use
is done, by observing
and acting on its exit condition
Run two tasks concurrently, creating a race between them and returns a pair containing both the winner's successful value and the loser represented as a still-unfinished fiber.
Run two tasks concurrently, creating a race between them and returns a pair containing both the winner's successful value and the loser represented as a still-unfinished fiber.
If the first task completes in error, then the result will complete in error, the other task being canceled.
On usage the user has the option of canceling the losing task, this being equivalent with plain race:
val ioA: IO[A] = ??? val ioB: IO[B] = ??? Concurrent[IO].racePair(ioA, ioB).flatMap { case Left((a, fiberB)) => fiberB.cancel.map(_ => a) case Right((fiberA, b)) => fiberA.cancel.map(_ => b) }
See race for a simpler version that cancels the loser immediately.
Start concurrent execution of the source suspended in
the F
context.
Start concurrent execution of the source suspended in
the F
context.
Returns a Fiber that can be used to either join or cancel the running computation, being similar in spirit (but not in implementation) to starting a thread.
Suspends the evaluation of an F
reference.
Suspends the evaluation of an F
reference.
Equivalent to FlatMap.flatten
for pure expressions,
the purpose of this function is to suspend side effects
in F
.
Operation meant for specifying tasks with safe resource acquisition and release in the face of errors and interruption.
Operation meant for specifying tasks with safe resource acquisition and release in the face of errors and interruption.
This operation provides the equivalent of try/catch/finally
statements in mainstream imperative languages for resource
acquisition and release.
is an action that "acquires" some expensive resource, that needs to be used and then discarded
is the action that uses the newly allocated resource and that will provide the final result
is the action that's supposed to release the
allocated resource after use
is done, irregardless of
its exit condition
Creates a cancelable F[A]
instance that executes an
asynchronous process on evaluation.
Creates a cancelable F[A]
instance that executes an
asynchronous process on evaluation.
This builder accepts a registration function that is being injected with a side-effectful callback, to be called when the asynchronous process is complete with a final result.
The registration function is also supposed to return
a CancelToken, which is nothing more than an
alias for F[Unit]
, capturing the logic necessary for
canceling the asynchronous process for as long as it
is still active.
Example:
import java.util.concurrent.ScheduledExecutorService import scala.concurrent.duration._ def sleep[F[_]](d: FiniteDuration) (implicit F: Concurrent[F], ec: ScheduledExecutorService): F[Unit] = { F.cancelable { cb => // Schedules task to run after delay val run = new Runnable { def run() = cb(Right(())) } val future = ec.schedule(run, d.length, d.unit) // Cancellation logic, suspended in F F.delay(future.cancel(true)) } }
Alias for suspend
that suspends the evaluation of
an F
reference and implements cats.Defer
typeclass.
Alias for suspend
that suspends the evaluation of
an F
reference and implements cats.Defer
typeclass.
Lifts any by-name parameter into the F
context.
Lifts any by-name parameter into the F
context.
Equivalent to Applicative.pure
for pure expressions,
the purpose of this function is to suspend side effects
in F
.
Executes the given finalizer
when the source is finished,
either in success or in error, or if canceled.
Executes the given finalizer
when the source is finished,
either in success or in error, or if canceled.
This variant of guaranteeCase evaluates the given finalizer
regardless of how the source gets terminated:
This equivalence always holds:
F.guarantee(fa)(f) <-> F.bracket(F.unit)(_ => fa)(_ => f)
As best practice, it's not a good idea to release resources
via guaranteeCase
in polymorphic code. Prefer bracket
for the acquisition and release of resources.
bracket for the more general operation
guaranteeCase for the version that can discriminate between termination conditions
Executes the given finalizer
when the source is finished,
either in success or in error, or if canceled, allowing
for differentiating between exit conditions.
Executes the given finalizer
when the source is finished,
either in success or in error, or if canceled, allowing
for differentiating between exit conditions.
This variant of guarantee injects an ExitCase in the provided function, allowing one to make a difference between:
This equivalence always holds:
F.guaranteeCase(fa)(f) <-> F.bracketCase(F.unit)(_ => fa)((_, e) => f(e))
As best practice, it's not a good idea to release resources
via guaranteeCase
in polymorphic code. Prefer bracketCase
for the acquisition and release of resources.
bracketCase for the more general operation
guarantee for the simpler version
Inherited from LiftIO, defines a conversion from IO
in terms of the Concurrent
type class.
Inherited from LiftIO, defines a conversion from IO
in terms of the Concurrent
type class.
N.B. expressing this conversion in terms of Concurrent
and
its capabilities means that the resulting F
is cancelable in
case the source IO
is.
To access this implementation as a standalone function, you can use Concurrent.liftIO (on the object companion).
Returns a non-terminating F[_]
, that never completes
with a result, being equivalent to async(_ => ())
Returns a non-terminating F[_]
, that never completes
with a result, being equivalent to async(_ => ())
Run two tasks concurrently and return the first to finish, either in success or error.
Run two tasks concurrently and return the first to finish, either in success or error. The loser of the race is canceled.
The two tasks are potentially executed in parallel, the winner being the first that signals a result.
As an example see Concurrent.timeoutTo
Also see racePair for a version that does not cancel the loser automatically on successful results.
Operation meant for ensuring a given task continues execution even when interrupted.
Operation meant for ensuring a given task continues execution even when interrupted.
(Since version 1.0.0-RC2) Use *> or productR instead.
(Since version 1.0.0-RC2) Use productREval instead.
(Since version 1.0.0-RC2) Use <* or productL instead.
(Since version 1.0.0-RC2) Use productLEval instead.
Type class for Async data types that are cancelable and can be started concurrently.
Thus this type class allows abstracting over data types that:
Due to these restrictions, this type class also affords to describe a start operation that can start async processes, suspended in the context of
F[_]
and that can be canceled or joined.Without cancellation being baked in, we couldn't afford to do it. See below.
Cancelable builder
The signature exposed by the cancelable builder is this:
CancelToken[F] is just an alias for
F[Unit]
and used to represent a cancellation action which will send a signal to the producer, that may observe it and cancel the asynchronous process.On Cancellation
Simple asynchronous processes, like Scala's
Future
, can be described with this very basic and side-effectful type and you should recognize what is more or less the signature ofFuture#onComplete
or of Async.async (minus the error handling):But many times the abstractions built to deal with asynchronous tasks can also provide a way to cancel such processes, to be used in race conditions in order to cleanup resources early, so a very basic and side-effectful definition of asynchronous processes that can be canceled would be:
This is approximately the signature of JavaScript's
setTimeout
, which will return a "task ID" that can be used to cancel it. Or of Java'sScheduledExecutorService#schedule
, which will return a JavaScheduledFuture
that has a.cancel()
operation on it.Similarly, for
Concurrent
data types, we can provide cancellation logic that can be triggered in race conditions to cancel the on-going processing, only thatConcurrent
's cancelation token is an action suspended in anF[Unit]
.Suppose you want to describe a "sleep" operation, like that described by Timer to mirror Java's
ScheduledExecutorService.schedule
or JavaScript'ssetTimeout
:This signature is in fact incomplete for data types that are not cancelable, because such equivalent operations always return some cancellation token that can be used to trigger a forceful interruption of the timer. This is not a normal "dispose" or "finally" clause in a try/catch block, because "cancel" in the context of an asynchronous process is concurrent with the task's own run-loop.
To understand what this means, consider that in the case of our
sleep
as described above, on cancellation we'd need a way to signal to the underlyingScheduledExecutorService
to forcefully remove the scheduledRunnable
from its internal queue of scheduled tasks, before its execution. Therefore, without a cancelable data type, a safe signature needs to return a cancellation token, so it would look like this:This function is returning a tuple, with one
F[Unit]
to wait for the completion of our sleep and a secondF[Unit]
to cancel the scheduled computation in case we need it. This is in fact the shape of Fiber's API. And this is exactly what the start operation returns.The difference between a Concurrent data type and one that is only Async is that you can go from any
F[A]
to aF[Fiber[F, A]]
, to participate in race conditions and that can be canceled should the need arise, in order to trigger an early release of allocated resources.Thus a Concurrent data type can safely participate in race conditions, whereas a data type that is only Async cannot do it without exposing and forcing the user to work with cancellation tokens. An Async data type cannot expose for example a
start
operation that is safe.Resource-safety
Concurrent data types are required to cooperate with Bracket.
Concurrent
being cancelable by law, what this means for the correspondingBracket
is that cancelation can be observed and that in the case of bracketCase the ExitCase.Canceled branch will get executed on cancelation.By default the
cancelable
builder is derived frombracketCase
and from asyncF, so what this means is that whatever you can express withcancelable
, you can also express withbracketCase
.For uncancelable, the cancel signal has no effect on the result of join and the cancelable token returned by ConcurrentEffect.runCancelable on evaluation will have no effect if evaluated.
So
uncancelable
must undo the cancellation mechanism of cancelable, with this equivalence:Sample:
When doing bracket or bracketCase,
acquire
andrelease
operations are guaranteed to be uncancelable as well.