The reason the thread-per-connection approach is nice is because it correctly propagates backpressure. If we're copying data from a source to a sink (let's say reading it in from the network and writing to a file), it's possible that the production of data may outstrip the consumption. If this happens, we need to make sure the producer slows down, or we risk running out of memory. In Java, the producer is typically connected to the consumer via a blocking queue, and if the queue fills up the producer can't send anything more to the consumer. A Java socket is one such queue, and if it fills up it will exert backpressure via TCP. This will work no matter how many queues or other mechanisms separate the producer and consumer.
However, every attempt I've seen to marry core.async to an async network stack has been fundamentally broken, in that it doesn't do this. Often, they'll just use 'put!', which works fine until the channel's queue fills up, and 1024 pending puts are accumulated, and finally the channel throws an exception. Alternately, they'll use a blocking put on the channel, which means that any backpressure will also extend to whatever other connections are sharing that thread or the thread pool. Note that the software that uses core.async in this way may work flawlessly in a wide variety of cases, but there's still an intractable failure mode lying in wait.
In some cases, such as http-kit's websocket mechanism, there's no way to even exert backpressure (you register a callback, and have no way to indicate in your callback that you can't handle more messages). This means that any attempt to use http-kit in conjunction with core.async will be subtly but fundamentally broken. Arguably, even without core.async in the equation it's broken. This is not a good state of affairs. I'll admit that it took me a few failures in production to realize how important correct handling of backpressure is, but this isn't something that our ecosystem can afford to ignore, especially as Clojure is used for larger-scale projects.
I will note that I am working on a solution to this, in the form of the upcoming Aleph release [1]. This will model every network connection via streams that can trivially be converted into core.async channels [2], and which exert backpressure over TCP wherever necessary without requiring a thread per connection. A formal beta should be available in the near future (it's already handling billions of requests a day in production without issue).
Zach