> I assume a real TLS implementation would use a thread pool or coroutines or something to manage this.
That's a very strange assumption. Depending on the API, the ones I've used will either just read in a loop until the length is fulfilled or an error occurs;
When you're receiving from a network socket over the Internet, blocking a (real) thread until all the data arrives is pretty inefficient.
or return an "incomplete message" error meaning that the caller is the one to continue reading.
That's pretty un-user-friendly.
There might be rare cases where a caller really needs precise control, but I'd expect any serious general-purpose library in a serious general-purpose language to "use a thread pool or coroutines or something to manage this". In the overwhelmingly common case what you want while waiting for data from the Internet is to yield to other fibers; a library should guide you towards doing the right thing and make the easy case easy.
When you're receiving from a network socket over the Internet, blocking a (real) thread until all the data arrives is pretty inefficient.
Yes, but it's still how the overwhelming majority of network code functions. It's not really till the rise of libev/libuv and friends that people start moving to non-blocking as a default (I spent pretty much an entire year of my life convincing an AWS team to reclaim 4 GB of thread stacks by moving to non-blocking I/O).
> or return an "incomplete message" error meaning that the caller is the one to continue reading.
That's pretty un-user-friendly.
It's also how all non-blocking I/O worked prior to languages adding native async functionality.
Yes, but it's still how the overwhelming majority of network code functions. It's not really till the rise of libev/libuv and friends that people start moving to non-blocking as a default
It's also how all non-blocking I/O worked prior to languages adding native async functionality.
Meh. AOLServer showed that you could do better back when I was in high school. I've given up worrying about ecosystems that haven't got it yet.
When you're receiving from a network socket over the Internet, blocking a (real) thread until all the data arrives is pretty inefficient.
I'm perplexed at this statement, and the rest of your post in general. How is that "inefficient"? What else can the thread do if it needs to process data that hasn't arrived yet?
On the other hand, I've rewritten a lot of code where someone thought adding lots of complexity to a fundamentally simple task would somehow be better, and gotten some real performance gains from it. Almost always, the straightforward and simple approach wins.
I'm perplexed at this statement, and the rest of your post in general. How is that "inefficient"? What else can the thread do if it needs to process data that hasn't arrived yet?
Some other task, such as processing data from a different socket that has arrived now. A library monopolising a thread for this one operation is like those DOS-era applications that expected to monopolise the whole CPU for their application - sure, it's "simpler", but it's vastly less efficient.
(And doing your network I/O async should not be complex or confusing in any serious modern language)
Comments
When you're receiving from a network socket over the Internet, blocking a (real) thread until all the data arrives is pretty inefficient.
That's pretty un-user-friendly.
There might be rare cases where a caller really needs precise control, but I'd expect any serious general-purpose library in a serious general-purpose language to "use a thread pool or coroutines or something to manage this". In the overwhelmingly common case what you want while waiting for data from the Internet is to yield to other fibers; a library should guide you towards doing the right thing and make the easy case easy.
Yes, but it's still how the overwhelming majority of network code functions. It's not really till the rise of libev/libuv and friends that people start moving to non-blocking as a default (I spent pretty much an entire year of my life convincing an AWS team to reclaim 4 GB of thread stacks by moving to non-blocking I/O).
It's also how all non-blocking I/O worked prior to languages adding native async functionality.
Meh. AOLServer showed that you could do better back when I was in high school. I've given up worrying about ecosystems that haven't got it yet.
When you're receiving from a network socket over the Internet, blocking a (real) thread until all the data arrives is pretty inefficient.
I'm perplexed at this statement, and the rest of your post in general. How is that "inefficient"? What else can the thread do if it needs to process data that hasn't arrived yet?
On the other hand, I've rewritten a lot of code where someone thought adding lots of complexity to a fundamentally simple task would somehow be better, and gotten some real performance gains from it. Almost always, the straightforward and simple approach wins.
Some other task, such as processing data from a different socket that has arrived now. A library monopolising a thread for this one operation is like those DOS-era applications that expected to monopolise the whole CPU for their application - sure, it's "simpler", but it's vastly less efficient.
(And doing your network I/O async should not be complex or confusing in any serious modern language)