Hacker News new | ask | show | jobs
by tightbookkeeper 585 days ago
But most windows 98 era Ui programs were 1 or 2 threads…. You just handle events in order in a loop.

It works and is far more responsive than what we have today.

> Disks are certainly not quick enough to have File.Delete(...) be blocking

What if you invoke a delete and then it fails and you want the user to respond? What will the state of your UI be when that happens?

2 comments

> What will the state of your UI be when that happens?

If you can't do anything else until you know whether it was a success or failure, then you ensure that. E.g. you disable every single button that allows the user to do something else before the previous operation completes. Basically the theory is usually that you can allow the UI to "read" the program state while a "write" operation is still in flight. Typically this results in the user being able to for example scroll a document so it re-renders correctly etc. After the in-flight operation succeeds/fails, you can show the user the message if required, then enable new operations to happen. But the UI never stopped pumping messages so it was always responsive at least.

> you disable every single button that allows the user to do something else before the previous operation completes.

Wow you mean the whole program becomes unresponsive? Crazy!

To address your main point, yes, scrolling, hover, etc can continue to work. But now you genuinely have two things your program is doing at once, and these must be coordinated.

A gui framework typically handles this, with a separate thread (or separate OS process). So your thread that responds to events can block while the render/refresh continues doing its thing.

With this design the problem goes away. Instead of writing code that disables the ui, issues a callback, waits to respond, you just literally write:

If (!file.delete()) { Showerror() }

This is the kind of code you can read, and put breakpoints on.

> Wow you mean the whole program becomes unresponsive? Crazy!

Yes a normal single threaded GUI normally becomes unresponsive if the user invokes blocking IO on the main (UI) thread. By "unresponsive" in this context I mean "does not process messages the message queue". That the user can't e.g. perform a certain operation is in this context not the same kind of "unresponsive". It responds (it could even tell him that he can't do it, or why he can't). It would be unresponsive if it gave the appearance that he could do something, but when he tries to, the UI doesn't respond and start the operation he requests.

> Instead of writing code that disables the ui, issues a callback, waits to respond, you just literally write: If (!file.delete()) { Showerror() }

That's typically how I'd write code regardless of whether it's explicitly async. "Disabling everything" usually isn't necessary, what you disable is of course the operations thare logically forbidden to perfom until the first operation completes. In a perfect world you don't have those. But often, you do.

> Wow you mean the whole program becomes unresponsive? Crazy!

It is using all resources to do what it was told to.

Results depend on the magnitude of the task and the hardware available with a very large overlap where the difference doesn't matter at all.

If blowing up complexity everywhere to solve a problem you probably wont have is a good thing is left as an exercise for the reader.

I agree. The right thing to do is to wait for the task to finish. I wrote that first line in jest,

I’m making fun of the notion that blocking = slow = unresponsive.

Precisely!

I had lots of pending requests, the goal was to have as many as possible (since the whole job took about 30 min) without freezing the UI.

When the callback happens there is work to do. The pattern is to do this work immediately.

Then there were as many as [not] possible bits of work to do simultaneously. Since the amount of work per job is unpredictable deliberately making the amount of simultaneous jobs unpredictable is insanity.

Synchronously I can do [say] 50 requests per second, parse 55 and have a buffer.

The solution to the riddle is not to limit the number of requests by 90% and extend the task to take 5 hours while not using 90% of the resources. Then UI freezes only become less frequent, they don't go away.

Instead I store all data from all callbacks in an array along with a description and use a setInterval to parse a configurable number of responses per second while adjusting the new requests to the size of the backlog.

But then it isn't really async anymore.