Swift added its own Swift Concurrency Model in Swift 5.5. If you are unfamiliar with it, you should likely go read up on it first. If you are still interested in learning Flynn after that, please continue :)
To use Flynn make sure you are using Swift 5.6 or later and make the following changes to your Package.swift
Add to your Package:
dependencies: [
.package(url: "https://github.com/KittyMac/Flynn.git", from: "0.3.0"),
]
Add to the desired Target:
.target(
...
dependencies: [
"Flynn"
],
plugins: [
.plugin(name: "FlynnPlugin", package: "Flynn")
]
)
Flynn grafts Actor-Model programming onto Swift, providing safety and performance for your highly concurrent Swift code. Flynn is heavily inspired by the Pony programming language. Here's what you need to know:
Using Actors to separate concurrent logic provides safety, performance, and efficiency.
class ConcurrentDatastore: Actor {
// Everything inside this actor is safe and cannot
// be accessed concurrently by any other thread
private var storage: [String: String] = [:]
...
}
Actors provide behaviors (which look like normal method calls at the call site) that execute asynchronously from the caller's perspective.
let datastore = ConcurrentDatastore()
datastore.beStore("SomeKey", "SomeValue")
From the Actor's perspective, behaviors execute synchronously (in the same order they are sent for the calling code).
class ConcurrentDatastore: Actor {
...
// Behaviors are called asynchronously but execute synchronously on the Actor
internal func _beStore(_ key: String, _ value: String) {
storage[key] = value
}
}
Unlike other attempts to bring Actor-Model programming to Swift, Flynn does not use DispatchQueues. Instead, Flynn includes a modified version of the Pony language runtime. This makes actors in Flynn much more light-weight than DispatchQueues; you can have millions of actors all sending messages to each other incredibly efficiently.
The Flynn library provides the mechanisms for safer concurrency and the FlynnPlugin will help ensure that safety for you at compile time. This keeps you out of numerous concurrency pitfalls by not allowing unsafe code to compile:
In this example, we have a public variable on our Counter Actor. Public variables are not allowed as they can be potentially accessed from other threads, breaking the concurrency safety the Actor-Model paradigm provides us.
RemoteActors are an advanced topic and are likely useful only to a subset of developers.
As of v0.2 Flynn has a new kind of actor, the RemoteActor
. RemoteActors behave similarly to Actors; they have internal state which is concurrency safe and you interact with them by calling behaviors. RemoteActors are intended to execute outside of your normal Flynn environment, usually that's in another process running on an different machine. Since RemoteActors run elsewhere, they are more restrictive then normal Actors (for instance, you cannot choose to unsafely expose access RemoteActors). Please see the RemoteActor documentation for more details.