skypjack
skypjack

Reputation: 50550

libuv and uv_try_write: why multiple buffers?

Consider the documentation of uv_try_write (the same applies for uv_write and uv_write2 as well).
The declaration is:

int uv_try_write(uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs)

Where uv_buf_t is a data structure that has at least the following fields:

I'm quite sure I'm missing something here.

What's the reason for which one should submit more than one uv_buf_t structure instead of a bigger one?
In other terms, if I have 100 char to write out, why should I submit 10 uv_buf_t containing each 10 char instead of a uv_buf_t containing 100 char?

It would be helpful a real world example in which such a choice makes sense, for I can't figure out it while reading the documentation.

Upvotes: 3

Views: 1017

Answers (2)

o11c
o11c

Reputation: 16136

Whenever you perform formatted I/O, all you are doing is concatenating a bunch of small strings.

Think about what is happening under the hood when you write something like

fprintf(stdout, "Hello, %s!\n", getenv("USER"));

This could be implemented (ignoring the multiple evaluation of getenv) as:

struct iovec bufs[3] = {{"Hello, ", 7}, {getenv("USER"), strlen(getenv("USER"))}, {"!\n", 2}};
writev(STDOUT_FILENO, bufs, 3);

(in practice, FILE operations are a little more complicated - perhaps unnecessarily so - but most cases are this simple).

Allowing multiple buffers to be specified directly means that you don't have to waste process time (or source code complexity) allocating a single buffer to hold them all before writing.


Also, have you ever run an compiler under make -j such that its output gets hugely messed up? That is generally caused because they do not do this - instead they emit several individual writes and they get mixed with writes from parallel processes, rather than emitting each line during a single syscall.

Upvotes: 2

saghul
saghul

Reputation: 2010

Most applications probably use a single one, but since writev is a thing we expose it in the try variant as well. Imagine an application which behaves as a proxy, and gets data in multiple packets which it then needs to relay. Sensing all buffers belonging to the same packet in a single go limits the syscalls to 1, instead of having to allocate space for all buffers, then copying over the content just to call write.

You can read more about the approach here: https://en.wikipedia.org/wiki/Vectored_I/O

Upvotes: 1

Related Questions