go_channels 1.0.3
go_channels: ^1.0.3 copied to clipboard
Go-style concurrency for Dart: typed channels, a faithful select over many channel operations, and structured task scopes with cooperative cancellation.
1.0.3 #
example/cancellation.dartshows aselectlosing a race without leaking the loser. That is the case the README makes against hand-rolledCompletercode, and nothing in the examples demonstrated it. Docs and example only.
1.0.2 #
No library code changed in this release. lib/ is byte-identical to 1.0.1.
example/select_multiway.dartis new. It takes the question "why notFuture.anyover tworeceive()calls" and answers it by running both spellings side by side, four scenes on fresh channels each time. TheFuture.anyrace drains both channels before it picks a winner: the losing value goes to a future nobody awaits, both producers see a successful send, and nothing throws.selectruns one branch and withdraws the rest, and the loser's value stays in its channel for the next receiver. When nobody is ready and a deadline wins instead, five rounds ofselectleave zero waiters parked while five rounds of theFuture.anyspelling leave five on each channel. The tie scene runs 2,000 rounds with both branches ready; one run split them 973 to 1027, and declaration order carries no priority.- The README's
selectsection now leads with that comparison and quotes the example's output, in place of a two-sentence nod to Go.
1.0.1 #
- Fix the two README diagrams, which were broken on pub.dev. Both pointed at
github.com/Yusufihsangorgel/channels— the repository name the package was developed under, before pub.dev rejected it as too close tochanneland it becamego_channels(see 0.1.1). That repository does not exist, so pub.dev's image proxy served a 404 for the buffered-versus-unbuffered diagram and for the capacity chart, in the two places where they carry the explanation. Thescreenshots:entries in the pubspec use archive-relative paths and were never affected, which is why both images still appeared in the thumbnail gallery while the README showed neither. Docs only; no code change.
1.0.0 #
The API is stable. No behaviour changes; this freezes the surface after an adversarial pass over the three primitives, and pins what it found as tests.
Verified by execution and now covered by test/contract_test.dart — mostly the
cases that deadlock when they are wrong:
- Channels. Sending on a closed channel throws, as does closing twice.
receiveon a closed and drained channel throwsChannelClosedError, whilereceiveOrreports closure instead. Values already buffered still drain after a close, so closing loses nothing. A receive that is already waiting completes (withok: false) when the channel closes rather than hanging, and a waiting send fails rather than hanging. - select.
onDefaultmakes it non-blocking; a closed channel counts as a ready receive rather than stalling the select; and when several branches are ready it picks at random, which the test pins statistically — a first-ready-wins implementation would fail it. - Task scopes. A failing task cancels its siblings' tokens and the first
error is rethrown from the scope;
withTimeoutcancels the token it hands out.
The status note in the README, which still claimed 0.1.0, now says what freezing
means here: every public type is final, so the planned shared-memory execution
path can be added without breaking callers. No runtime dependencies.
0.2.2 #
- Add
example/README.mdfor pub.dev's Example tab (it was empty). It walks through the fan-out/fan-in example — a producer, a scope of four workers, and aselect-based collector — with the real output. Also fixes the stale run command in the example's doc comment. Docs only.
0.2.1 #
-
Add
benchmark/capacity_benchmark.dartand document what buffer capacity actually buys. Moving 200,000 values from one task to another, every buffered size (1, 16, 256, 4096) lands within a few percent of every other and about 10% above the unbuffered rendezvous, and draining throughselectmeasured slightly faster than a directreceive. Capacity is a backpressure decision, not a throughput one, and the README now says so with the chart.Two things the benchmark had to get right to be worth reading: the plain case drains with
receiveOrrather thanch.stream, because the stream wraps every value in aStreamControllerevent and would have measured Dart's stream machinery instead of the channel; and every case asserts it moved all 200,000 values, so the rows are comparable. The claim that a waiting rendezvous does not block the isolate is measured too — a 1 ms timer fires 20 times in 20 ms with asendoutstanding.
0.2.0 #
- Seal the public types.
Channel,SelectCases,TaskScope,CancelToken,ChannelClosedErrorandCancelledExceptionare nowfinal. None is meant to be subtyped — a channel's guarantees come from its implementation, not from an interface — and doing this now, while the package is young, keeps every future field from being a breaking change for a subclasser later. Nothing in the package, its tests, its example or its benchmark subtypes any of them. No behaviour change.
0.1.1 #
First pub.dev release. The package was developed under the name channels,
which pub.dev rejects as too similar to the existing channel package, so it
is published as go_channels. The import is
package:go_channels/go_channels.dart; the API is unchanged.
- Add a diagram to the README, and declare it as a pub.dev screenshot, showing
the one thing that separates an unbuffered channel from a buffered one: when
sendcompletes. Unbuffered rendezvous —sendfinishes at the receive; buffered letssendreturn while the buffer has room, and blocks only when it is full.
0.1.0 #
- Initial release.
Channel<T>: buffered and unbuffered channels withsend,receive,receiveOr(Go-stylevalue, ok), astreamview, andclose.select: waits on several channel receives/sends at once and runs exactly one, withonDefault(non-blocking) andonTimeoutbranches; random choice among ready branches for fairness.- Structured concurrency:
withTaskScopeandwaitAllrun a group of tasks fail-fast,CancelTokenprovides cooperative cancellation, andwithTimeoutcancels on a deadline.