Beware: I recently ran into an issue where the root cause was that creating two timeout channels actually only created one which was returned by the second call. To illustrate:
(identical? (async/timeout 10) (async/timeout 9)) => true
The fact that the resolution (on the JVM) is only 10ms is not a problem itself, but the "recycling" of existing timeout objects bit me hard when I used them as keys in a map to lookup an associated "event" to complete. In a value-based world, I can kinda see why this is the case, but it was still surprising given the lack of documentation.there is only 1 timeout channel currently
huh?
one per instant (with 10ms resolution), right?
a quick fix work around is to replace (async/timeout ...) with (async/go (async/<! (async/timeout ...)))
Yes, hiredman, that would work. But it seems wasteful... perhaps I need to get over that.
Ultimately I refactored my code to associate multiple events with a single channel to overcome the lack of uniqueness by timeout channel.
and for designs where you use timeout as a key like {some-timeout some-data} and do an alts! over a bunch of timeouts and then lookup the data in the map, something like a set of (async/go (async/<! (async/timeout ...)) some-data) is often nicer
That ^ is pretty much exactly my use case. My solution ended up being {(async/timeout n) [collection of things associated with the same timeout].
yeah, too much work to figure out how to associate things with the same timeout 🙂
It was added complexity, for sure. But I couldn't bring myself to add the overhead of the "unique relay channel" approach you conceived -even if I had been quick enough to come up with it on my own last night.
https://gist.github.com/hiredman/a68a2add9751eb8de3d2776363219e13 is an example of wrapping timeouts to have them convey data when they timeout, although maybe be obfuscated
I think I have 1 or 2 patches in the core.async jira that incidentally change timeouts to be unique
like, I think the commit that changed timeouts to behave like they do was aimed at reducing the memory usage from using timeouts in tight loops, but my patches on https://clojure.atlassian.net/browse/ASYNC-234 solve that much more comprehensively. but apparently rich hates anything called a "nack", which is the mechanism added there to clean up timeouts that aren't being actively waited on.
https://clojure.atlassian.net/browse/ASYNC-109 is a much smaller patch that basically just wraps the existing timeout stuff in a non-closable ReadPort, which would also cause timeouts to be unique objects