Hacker News new | ask | show | jobs
by insanitybit 1011 days ago
> But nobody wants to write a library that isn't "web-scale" anymore, so tough luck.

It's more like "I want to be able to put timeouts in my code". 99% of why I want async is so that if something takes too long I can just stop that. That is incredibly hard to do without async.

2 comments

Not sure about Rust, but in other languages that don't have async: create a queue, spawn a thread with your task, thread with sleep and wait for a message from any of those two. Kill the still running thread when you get the message. Can't say it's incredibly hard (unless it's Javascript or you work in a single-threaded model in general).
> Kill the still running thread when you get the message

This is extremely difficult. I mentioned elsewhere that the only way to kill a thread is through the pthread_cancel API, which is very dangerous.

Languages with larger runtimes can get around this because they have all sorts of things like global locks or implicit cooperative yielding. So they don't ever have to "kill" a thread, they actually just join it when it yields.

As I understand when you are blocked on I/O and sends a signal to the waiting thread, that system call will simply be released and return an error. Ruby (Java etc.) does make it simple because of GC, so I don't need to worry about file descriptor leaks etc. But talking about Rust, shouldn't it be a part of a thread management? Basically if an error happens during normal blocking system call, it goes through the same sequence, no? E.g. you have to release any thread-local allocations no matter by each way system call was terminated. Rust threads are supposed to be memory safe, not sure about file descriptors. I don't quite understand what you mean by "yielding" though.
Genuinely curious: looks to me like you can set timeout on sockets (TcpStream) with std. Does that not work? What other kinds of timeouts do you typically need?
Relying on the socket APIs is a bit painful. For one thing, what if that socket is shared across tasks? What if I want to do per-request timeouts? What if I don't want to expose the socket APIs to callers?

What if my work isn't related to socket timeouts? For example, downloading a multi-part file? I may want a very long socket timeout but still have a distinct timeout for the individual chunked operations. It might take 30 seconds to grab an entire file but if one chunk takes >3 seconds I may want to time out.

What if my work involves no IO at all?

The ability to cancel work in progress is extremely important to me.

> For one thing, what if that socket is shared across tasks?

Yeah that’s an issue. In Go they sync it (thread safe), which in Rust would translate to interior mutability.

> What if I want to do per-request timeouts?

Ah you’re right in http2 there can be multiple concurrent reqs per conn. Go still allows request based timeouts, but I wonder if that’s possible with the limited primitives in std. It’s also true that this is a case where the inner conn should not be exposed.

> I may want a very long socket timeout but still have a distinct timeout for the individual chunked operations.

Right! That’s typically done by extending the deadline for every chunk. Ie the user/caller needs a way to set timeouts.

> The ability to cancel work in progress is extremely important to me.

Yes for sure. I was just curious. Btw which libs are you referring to for network requests? I’d like to see their APIs.

> Btw which libs are you referring to for network requests?

Consider this: https://docs.rs/rusoto_s3/latest/rusoto_s3/trait.S3.html

You're given a trait and, understandably, this trait does not expose any sockets to you (it may not even be backed by sockets).