The asynchronous nature of the read/write I think I understood before. 
As mentioned in the talk, it seems Node.js will buffer/queue data 
internally and return a "recommendation" for the user to stop sending 
in case its hitting the socket write limits.

Anyway, since there's still some (small) overhead in performing the 
reads and writes to the sockets (even when they're ready), the main 
thread will be busy for a while and it won't service other requests in 
the mean time.

That's what I found odd about the single-thread thing when I first read 
about it (and why I asked these questions). But after watching the 
talk, in which it's mentioned you're supposed to scale in the number of 
instances/processes (not threads) in this architecture, I think I get 
it :)

Once again, thank you for the answers!

On Wednesday, January 22, 2014 3:09:21 PM UTC-2, Fedor Indutny wrote:
>
> I think it is quite correct. But there are some nuances, actually 
> writes and reads are non-blocking. Libuv will queue everything until 
> the OS will tell it that data could be read/written. So the most 
> *blocking* thing here is a user callbacks, and that means that 
> everything is up to you! ;) 
>
> On Wed, Jan 22, 2014 at 9:06 PM,  <[email protected] <javascript:>> 
> wrote: 
> > Ok, after reading more on of the source code, watching the Google Tech 
> > Talk on Node.js and considering your answers, this is a rough attemp to 
> > make sense of what happens in libuv when you have, for instance, a HTTP 
> > request asking for a file (assume Node.js using libuv): 
> > 
> > 1) The default event loop listening to TCP connections will run the 
> > callback for accepting the connection. 
> > 
> > 2) The connection is accepted, and the OS notifies that there's data to 
> > be read in the socket. 
> > 
> > [default loop dealing with other requests...] 
> > 
> > 3) The request (data) will be read in the main thread up to a certain 
> > limit to avoid starvation (32 iterations, as in `uv__read`). 
> > 
> > 4) The user callback will be called inside this libuv callback, still 
> > in the main thread. It will parse the request, and upon finding that it 
> > should read a file, will call the FS abstraction asking for that file. 
> > If we assume Node.js here, this callback means a V8 invocation running 
> > in the main thread, and no other requests can be served in the mean 
> > time. 
> > 
> > 5) The call to read a file will spawn asynchronous work by calling 
> > `uv__work_submit`. The task will be performed in another thread, and 
> > `uv_sync_asend` will send the file contents through a socket (pipe?) 
> > when it's done. 
> > 
> > [async request running and default loop dealing with other requests...] 
> > 
> > 6) The file contents will be received by a watcher in the main thread, 
> > and the default event loop will read it all and call the user callback 
> > with the file contents. No requests can be served while we're doing 
> > that. 
> > 
> > 7) The user callback (still running in the main thread) will write the 
> > response to the client. No requests can be served while we're doing 
> > that. 
> > 
> > 
> > I think I may have mistaken some parts, especially in step 4 and in the 
> > parts where requests can't be served in steps 6 and 7. I'm assuming a 
> > small request and a small file. 
> > 
> > Is this more or less correct or did I get it all wrong? 
> > 
> > 
> > Thank you for the patience :) 
> > Allan 
> > 
> > On Wednesday, January 22, 2014 9:18:06 AM UTC-2, Fedor Indutny wrote: 
> >> 
> >> I mean using the same TCP server fd in multiple threads each with it's 
> >> own libuv loop. You'll still need to send the `uv_tcp_t` server handle 
> >> to other threads using IPC pipe (see `uv_pipe_open`). 
> >> 
> >> On Wed, Jan 22, 2014 at 3:14 PM,  <[email protected]> wrote: 
> >> > What do you mean by listening on the same fd? 
> >> > 
> >> > I have used the other approach when using libevent (one event loop 
> >> > giving 
> >> > control of the fds to other event loops in other threads). 
> >> > 
> >> > On Wednesday, January 22, 2014 9:11:29 AM UTC-2, Fedor Indutny wrote: 
> >> >> 
> >> >> Hello again! 
> >> >> 
> >> >> Sorry for not answering all of your questions. 
> >> >> 
> >> >> libuv is a single-threaded library, and everything, except, 
> >> >> uv_work_cb's are executed in the same thread, where uv_run() "runs". 
> >> >> There are at least two ways, how you could make libuv-based app use 
> >> >> all available CPUs: load-balancing incoming sockets via IPC pipes to 
> >> >> child process or worker threads (each with it's own libuv loop) or 
> >> >> listening on the same fd. 
> >> >> 
> >> >> Node.js was using latter approach up until v0.11 that will become 
> v0.12 
> >> >> soon. 
> >> >> 
> >> >> Cheers, 
> >> >> Fedor. 
> >> >> 
> >> >> On Wed, Jan 22, 2014 at 3:02 PM,  <[email protected]> wrote: 
> >> >> > Thank you for the answers! I used libevent previously, so I was 
> >> >> > confused about the different nature of libuv. 
> >> >> > 
> >> >> > I took a look at the NodeJS source code, and how it uses libuv, 
> and 
> >> >> > one 
> >> >> > question remains. 
> >> >> > 
> >> >> > Is the default event loop/main thread used for everything? 
> Assuming a 
> >> >> > request comes in, this thread alone will: get notified about the 
> >> >> > event, 
> >> >> > read the data, run the callback, and then write back a response? 
> All 
> >> >> > of 
> >> >> > this on a single thread, for any number of requests? 
> >> >> > 
> >> >> > I read parts of the NodeJS code, but I couldn't find anything that 
> >> >> > points to any thread parallelism (except from debugging). It seems 
> >> >> > that 
> >> >> > even uv_queue_work is not even being called much. 
> >> >> > 
> >> >> > 
> >> >> > If this question is too specific, let me know and I'll ask it in 
> the 
> >> >> > NodeJS mailing list. 
> >> >> > 
> >> >> > 
> >> >> > Allan 
> >> >> > 
> >> >> > On Friday, January 17, 2014 4:35:40 PM UTC-2, Fedor Indutny wrote: 
> >> >> >> 
> >> >> >> Hello! 
> >> >> >> 
> >> >> >> You should not call anything except `uv_async_send()` from 
> another 
> >> >> >> thread. Many functions are inserting stuff into loop's linked 
> lists 
> >> >> >> and the list itself is not thread-safe (not even talking about 
> many 
> >> >> >> other internals). 
> >> >> >> 
> >> >> >> `uv_async_send()` indeed writes to one end of the pipe, and libuv 
> is 
> >> >> >> listening on the other end of the pipe, and interrupts loop and 
> >> >> >> invokes callback when receives data. 
> >> >> >> 
> >> >> >> As a way to return data back from uv_work_cb - you could set and 
> >> >> >> change req.data safely inside worker thread, it'll be available 
> in 
> >> >> >> uv_work_done_cb. 
> >> >> >> 
> >> >> >> Cheers, 
> >> >> >> Fedor. 
> >> >> >> 
> >> >> >> On Fri, Jan 17, 2014 at 6:19 PM,  <[email protected]> wrote: 
> >> >> >> > Hi, 
> >> >> >> > 
> >> >> >> > I've been curious about how libuv works internally regarding 
> >> >> >> > thread 
> >> >> >> > communication. 
> >> >> >> > 
> >> >> >> > This is what I understand: 
> >> >> >> > There's a single thread running uv_run. If I spawn some work to 
> be 
> >> >> >> > done 
> >> >> >> > in another thread I'm supposed to use uv_queue_work. The way to 
> >> >> >> > send 
> >> >> >> > the results of this work back to the main thread is through 
> >> >> >> > uv_async_send (which is the only thread-safe function in 
> libuv). 
> >> >> >> > 
> >> >> >> > This is what I want to do: 
> >> >> >> > Start listening on a TCP socket, accept incoming connections in 
> >> >> >> > the 
> >> >> >> > default loop, and wait for data to be available for reading 
> (using 
> >> >> >> > uv_read_start). When it's available for reading, I'd put the 
> work 
> >> >> >> > (socket reading) in the queue (with uv_queue_work), and the 
> >> >> >> > callback 
> >> >> >> > for this would run in another thread, reading the data and 
> >> >> >> > performing 
> >> >> >> > some work based on it, which may involve writing data back to 
> this 
> >> >> >> > or 
> >> >> >> > any other socket. 
> >> >> >> > 
> >> >> >> > So, my questions related to this are: 
> >> >> >> > - Is this possible to do? If I call uv_read_start and uv_write 
> in 
> >> >> >> > another thread, can this cause trouble, because they should 
> have 
> >> >> >> > been 
> >> >> >> > called in the default loop? 
> >> >> >> > 
> >> >> >> > - If uv_read_start and uv_write should be called in the default 
> >> >> >> > loop, 
> >> >> >> > then the main thread will be responsible for reading and 
> writing 
> >> >> >> > all 
> >> >> >> > data, right? Wouldn't this impact performance? How does NodeJS 
> >> >> >> > deal 
> >> >> >> > with this? 
> >> >> >> > 
> >> >> >> > - How does uv_async_send work? From a quick glance at the 
> source 
> >> >> >> > code, 
> >> >> >> > I suspect it sends data in a file descriptor, which will be 
> read 
> >> >> >> > in 
> >> >> >> > the 
> >> >> >> > default loop. Is this what is happening? 
> >> >> >> > 
> >> >> >> > 
> >> >> >> > Allan 
> >> >> >> > 
> >> >> >> > -- 
> >> >> >> > You received this message because you are subscribed to the 
> Google 
> >> >> >> > Groups 
> >> >> >> > "libuv" group. 
> >> >> >> > To unsubscribe from this group and stop receiving emails from 
> it, 
> >> >> >> > send 
> >> >> >> > an 
> >> >> >> > email to [email protected]. 
> >> >> >> > To post to this group, send email to [email protected]. 
> >> >> >> > Visit this group at http://groups.google.com/group/libuv. 
> >> >> >> > For more options, visit 
> https://groups.google.com/groups/opt_out. 
>

-- 
You received this message because you are subscribed to the Google Groups 
"libuv" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/libuv.
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to