• 0 Posts
  • 62 Comments
Joined 3 years ago
cake
Cake day: July 6th, 2023

help-circle

  • Fundamentally the issue is that Future is a n+m model where you have n virtual threads executing on m OS threads. As such traditional solutions to associating data to OS threads like thread locals don’t work as there’s no guarantee that a given virtual thread will continue to execute on any given OS thread.

    This is fully runtime/platform dependant and not true in many cases. Not only strictly single-thread runtimes exist, but async is already used in places like the embedded world where there is no OS for there to be OS threads, single or otherwise.

    It is for this reason that the extra trait bounds on the implicit impl Future return type in async functions have caused a lot of trouble (implicit Send, …etc). If for nothing else, adding context to the equation would make that situation more complex.

    In any case, attaching “metadata” to T: Future data (instead of the runtime or some other global context) doesn’t make any sense in my head, as one would be "await"ing around and the concrete return type is often hidden behind that impl Future. And if the data is really special and needs to be attached to T: Future, then it’s (conceptually) just data that is a part of T, not Future.


    • Rust doesn’t do implicit transparent structs. The FutureExt trait methods return a wrapper struct WithContext which is where the data (T) and the context are stored. One method takes context directly from an argument, the other clones one from a thread local. Data can’t hang in thin air to be attached to a triat. This also shows that the abstraction you (presumably) were asking about is both possible and already exists.
    • Forcing a context on all T: Future types would make the abstraction non-zero-cost in any case.







  • Nah. There was space for simple (in a good way) native (no VM) GC languages to set between scripted (python) and VM(-first) languages (java) on one side, and no-GC languages on the other. Not doing OOP and not doing exceptions were good decisions as a starting point. But the problem is that this was based on following C (instead of C++) and nothing else, making no use of decades of programming language research and development*. And it’s the (un)design that followed that ended up creating a horrible simple (in a bad way) language. And this google-branded language hogged that space where other better languages could have been developed, or those which got developed could have flourished more and gained more momentum. And the corporate marketing actually tried to sell every bad design aspect as a “akshually a feature”. For example, lack of generics was celebrated for years as great simplicity, until an almost deliberately bad implementation of generics got added later as you mentioned.

    tl;dr: The surface premise of the language was good and arguably needed at the time. What got delivered was bad.


    * An observant historian would point out here that some good (arguably better even) languages predate C itself (e.g. the ML family).


  • Go is not even good. It’s horribly designed (or rather, un-designed, since its creators actually boasted about deliberately doing the core part in what? a couple of weeks IIRC). If it wasn’t for the associated corporate brand, it would have been a dead meme in the eyes of everyone by 2015 when Rust hit v1.0 (It was born a meme in the eyes of those who know).

    And I mentioned that date to point out that we can’t call these languages new forever 😉 . In fact, if you took a snapshot of street tech talk from 10 years ago, you would see that these generic conventional unwisdom comparisons have been done to death already. Which then begs the question: what newfound “wisdom” needed to be added to these “muh best tool for the job” talking points? Or are we just testing the wisdom of our new best tool for all jobs, LLMs?



  • With GPU rendering, you should learn about GPU processing and memory usage too, not that it would matter much for such a use-case.

    nvtop is nice for displaying all that info (it’s not nvidia-specific).

    Also % CPU usage is not a good metric, especially when most people forget to set CPU frequencies to fixed values before measuring. And heterogenous architectures (e.g. big.LITTLE) make such numbers meaningless anyway (without additional context). But again, none of this really matters in this use-case.


  • A quick shallow look.

    • Avoid single hard paths. Provide fall-backs. Make them all configurable. Use xdg (properly)…etc.
    • Avoid .unwrap() or any source of panic!() for non-fatal things that can actually fail.
    • Make non strictly necessary fields optional in you model, if that helps.
    • Use .filter_map() and .collect() in your parsing code, instead of all the matches and continues in a for loop. You can use .ok()? to early-return with None on errors.
    • And finally, since you’re micro-benchmarking, try speedy or borsh instead of bincode, unless you need the serde compat for some reason.