Hi Zach, 

Thanks for the clarity of thought that went into this post. 

Perhaps it is obvious to everyone but me, but I saw this post by Christophe 
Grande yesterday that appears to address these concerns:
"Back-pressurized interop for 
core.async" https://twitter.com/cgrand/status/520566182194450432
https://gist.github.com/cgrand/767673242b7f7c27f35a

I'm interested to hear if this solves your problem or is about something 
else. 

Cheers
Julian

On Wednesday, 8 October 2014 17:00:02 UTC+11, Zach Tellman wrote:
>
> 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
>
> [1] https://github.com/ztellman/aleph/tree/0.4.0
> [2] https://github.com/ztellman/manifold
>
>
>
> On Tuesday, October 7, 2014 1:36:16 PM UTC-7, adrian...@mail.yu.edu wrote:
>>
>> It's not about 'safety' (depending on what that means in this context), 
>> but as Zach pointed out, if you aren't careful about backpressure you can 
>> run into performance bottlenecks with unrestrained async IO operations 
>> because although they let you code as if you could handle an unlimited 
>> amount of connections, obviously that isn't true. There is only a finite 
>> amount of data that can be buffered in and out of any network according to 
>> its hardware. When you don't regulate that, your system will end up 
>> spending an inordinate amount of time compensating for this. You don't need 
>> to worry about this with "regular io" because the "thread per connection" 
>> abstraction effectively bounds your activity within the acceptable physical 
>> constraints of the server. 
>>
>> On Tuesday, October 7, 2014 2:49:30 PM UTC-4, Brian Guthrie wrote:
>>>
>>>
>>> On Mon, Oct 6, 2014 at 12:10 AM, <adrian...@mail.yu.edu> wrote:
>>>
>>>> Zach makes an excellent point; I've used AsyncSocketChannels and its 
>>>> irk (
>>>> http://docs.oracle.com/javase/8/docs/api/java/nio/channels/AsynchronousServerSocketChannel.html),
>>>>  
>>>> with core.async in the past. Perhaps replacing your direct 
>>>> java.net.Sockets 
>>>> with nio classes that can be given CompletionHandlers (
>>>> http://docs.oracle.com/javase/7/docs/api/java/nio/channels/CompletionHandler.html)
>>>>  
>>>> would be a better fit. 
>>>>
>>>
>>> Once I do some performance instrumentation I'll give that a shot. I 
>>> admit that I'm not familiar with all the implications of using the nio 
>>> classes; were I to switch, is it safe to continue using go blocks, or is it 
>>> worth explicitly allocating a single thread per socket?
>>>
>>> Brian
>>>
>>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to