• Darq@social.icod.de
    link
    fedilink
    arrow-up
    1
    ·
    1 year ago

    @sugar_in_your_tea map not thread safe, because multiple threads iterate over one map so you have to use sync.Mutex to lock it for reading, writing or both. I fell into that pit too. Part of the learning process. C++ has mutexes too.

    • sugar_in_your_tea
      link
      fedilink
      arrow-up
      1
      ·
      1 year ago

      Right, the whole point of Go is to be concurrency friendly, as in, the main reason you’d use it is to do multi-threaded concurrency. That’s the #1 selling point and it’s why goroutines and channels are a thing. Yet there are so many little things you need to keep in mind, such as:

      • sending mutable types across channels - you either need to ensure it cannot be used by the sender until the receiver is done with it (either by coupling the logic, or by destroying the sender’s copy), or you need to copy it; then you get into whether you need a deep copy, and how to protect any other reference types you send; Rust solves it with the Copy and Send traits, which can only work if everything you depend on implements the Copy or Send trait
      • no scope guards, so you need to rely on defer for unlocking; in Rust, you get this for free, as soon as you lock something, it’ll unlock once your scope exits
      • a read from a nil channel blocks instead of panicing (ideally it would fail to compile) - that’s a pretty easy mistake to make

      Part of the learning process

      Unfortunately, you hit a lot of these cases in production instead of at compile time. In Rust, many of these types of issues are caught before you even get to testing your code, much less actually trying to ship something.

      That’s why my decision process is something like this:

      • Python - if I just want a quick prototype and don’t particularly care about production-level stuff like performance, safety guarantees, etc
      • Rust - once I need performance, safety guarantees, etc

      Go isn’t easy enough to just throw a junior developer on a project, and it’s not robust enough to catch a senior developer when they make mistakes. I thought it would’ve been good enough, but it’s just not as productive for me as Python (generally you hand-wave away the concurrency by using separate processes), and the compiler doesn’t catch nearly enough to rival Rust, so I’m happy to pay the productivity penalty to shift from Python to Rust once I know I need something a bit more serious. And once you’re experienced, the compiler doesn’t really get in the way anymore.

      Go is interesting I guess as a microservice tool where you’re making things that are small enough, but imo it really doesn’t scale all that well in terms of reducing bugs as the project gets larger.