Futures is a lightweight, general-purpose library for asynchronous programming in Swift, that provides a set of interoperable primitives to aid development of highly concurrent, performant and safe programs, both on the server and the desktop or mobile. Futures adopts a "pull"-based, demand-driven approach to asynchronous programming which, besides offering astounding performance, makes dealing with traditionally difficult to solve problems such as backpressure, cancellation and threading, trivial.
Documentation / A Quick Example / Requirements / Installation
There is a swath of libraries for asynchronous programming in Swift already. Many are fine libraries that you should be seriously considering if you're looking for an abstraction that fits your needs. So why should you care about Futures?
You will find that Futures...
Subject
, thank you).Read on, there's more in store:
Here's a small program that computes the Answer to the Ultimate Question of Life, the Universe, and Everything:
import Futures
let integers = Stream.sequence(0...)
let primes = integers.filter(isPrime)
var answer = primes.buffer(4)
.map { $0[0] * $0[1] * $0[3] }
.first(where: isPronic)
print(answer.wait()) // prints 42
Here's the same program contrived enough to showcase several types and concepts prevalent in Futures -- segregating tasks into different execution contexts, inter-task communication with channels, extracting the result from a remote task, and more. Find out more in the documentation. Share and Enjoy.
import Futures
// Create *executors* to spawn *tasks* on. Each QueueExecutor
// is backed by a private serial DispatchQueue.
let deepThought = (
cpu0: QueueExecutor(label: "CPU 0"),
cpu1: QueueExecutor(label: "CPU 1"),
cpu2: QueueExecutor(label: "CPU 2")
)
// Create two *channels* via which values can be communicated
// between parts of the program.
let pipe1 = Channel.makeUnbuffered(itemType: Int.self)
let pipe2 = Channel.makeUnbuffered(itemType: Int.self)
// Spawn a task that produces positive integers on one
// executor and sends the values to one of the channels.
let integers = Stream.sequence(0...)
deepThought.cpu1.submit(integers.forward(to: pipe1))
// Spawn another task on the second executor that receives
// these values, filters out non-prime integers and sends
// the remaining down the second channel.
let primes = pipe1.makeStream().filter(isPrime)
deepThought.cpu2.submit(primes.forward(to: pipe2))
// Spawn a third task on the third executor that receives
// the prime numbers via the channel and performs the actual
// computation of the answer. For this task, we ask for a
// handle back, with which we can get the final result or
// cancel it.
var answer = deepThought.cpu0.spawn(
pipe2.makeStream()
.buffer(4)
.map { $0[0] * $0[1] * $0[3] }
.first(where: isPronic)
)
// At this point, everything happens asynchronously in
// secondary background threads, so the program would just
// exit. We need the answer first however, so we block the
// current thread waiting for the result of the computation
// which we just print to standard output.
print(answer.wait()) // prints "Result.success(42)"
You'll need the following functions if you want to run the program yourself and experiment:
import Foundation
func isPrime(_ n: Int) -> Bool {
return n == 2 || n > 2 && (2...(n - 1)).allSatisfy {
!n.isMultiple(of: $0)
}
}
func isPronic(_ n: Int) -> Bool {
let f = floor(Double(n).squareRoot())
let c = ceil(Double(n).squareRoot())
return n == Int(f) * Int(c)
}
Futures requires Swift 5.0 (or newer) and can be deployed to any of the following platforms:
To integrate Futures with the Swift Package Manager, add the
following line in the dependencies list in your Package.swift
:
.package(url: "https://github.com/dfunckt/swift-futures.git", .upToNextMinor(from: "0.1.0"))
Note: Futures is in its early days and its public APIs are bound to change significantly. Until version 1.0, breaking changes will come with minor version bumps.
Then add Futures as a dependency of the targets you wish to use it in. Futures exports two separate modules:
Futures
: the core library.FuturesSync
: an assortment of thread synchronization primitives and
helpers. This module is currently highly experimental and its use is
discouraged.Here is an example Package.swift
:
// swift-tools-version:5.0
import PackageDescription
let package = Package(
name: "MyApp",
products: [
.executable(name: "MyApp", targets: ["MyTarget"]),
],
dependencies: [
.package(url: "https://github.com/dfunckt/swift-futures.git", .upToNextMinor(from: "0.1.0")),
],
targets: [
.target(name: "MyTarget", dependencies: ["Futures"]),
]
)
Futures is licensed under the terms of the MIT license. See LICENSE for details.
link |
Stars: 32 |
Last commit: 3 years ago |
assertNoError
combinatorsSwiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API | Analytics