1. 8
  1. 2
    1. How about detaching a thread that then simply blocks?
    let location = try userLocation()
    let conditions = try weatherConditions(for: location)
    let (imageData, response) = try URLSession.shared.data(from: conditions.imageURL)
    if (response as? HTTPURLResponse)?.statusCode == 200 {
        let image = UIImage(data: imageData)
    } else {
        // failed
    }
    

    The OS already has all these facilities, not sure why we have to recreate them from scratch in user space.

    1. Both Combine (Rx,…) and async/await map dataflow onto familiar and seemingly “easy” call/return structures. However, the more you make the code look like it is call/return, the further away you get from what the code actually does, making understanding such code more and more difficult.
    1. 3

      Apple points out in a Swift concurrency WWDC talk that wasting threads can have a much bigger impact on devices like iPhones. Having 100k worker threads on a modern Linux server isn’t a big deal at all. But on a RAM-constrained device trying to use as little energy as possible that’s not a good idea.

      Consider an app that needs to download 200 small files in the background (the example from the video linked above). Blocking in threads, that’s 100 MB of thread stacks alone, not to mention the OS-level data structures and other overhead. On a server that’s negligible. On a brand new 2021 iPhone with 4 GB of RAM that’s 1/40 of physical memory. 1/40 sounds small, but users run dozens of apps at a time. 1/40 of RAM can be 1/4 to 1/2 your entire memory budget for your app. Not a good use of resources.

      Update: both replies mention thread stacks are virtual memory, and likely won’t use the full 512 KB allocated for them. Which is a good point. Nevertheless, the async model has proven repeatedly to use less RAM and have lower overhead than a threaded model in multiple applications, most famously nginx vs Apache. Personally I think async/await has more utility on an iPhone than in 99% of web app servers.

      1. 2

        Thread stacks are demand paged.

        But even if they weren’t, userspace threads are a cleaner abstraction. Async and await is manual thread scheduling.

        1. 2

          That Apple statement, like a lot of what Apple says on performance and concurrency, is at best misleading.

          First, iPhones are veritable supercomputers with amazing CPUs and tons of memory. The C10K problem was coined in 1999, computers then had something like 32-128MB of RAM, Intel would sell you CPUs between 750MHz and 1GHz. And the C10K problem was considered something for the most extreme highly loaded servers. How are you going to get 10K connections on an iPhone, let alone 100K? No client-side workloads reasonably produce 100K worker threads. Wunderlist, for example, used a maximum of 3-4 threads, except for the times when colleagues put in some GCD, at which point that number would balloon to 20-40. Second, Apple technologies such as GCD actually produce way more threads than just having a few worker threads that block. Third, those technologies also perform significantly worse, with more overhead, than just having a few worker threads that block. We will see how async/await does in this context.

          For your specific example, downloading 200 (small) files simultaneously is a bad idea, as your connection will max out way before that, more around 10 simultaneous requests. So you’re not downloading any faster, you are just making each download take 20 times longer. Meaning you increase the load on the client and on the server and add a very high risk of timeouts. Really, really bad idea. If async/await makes such a scenario easier to accomplish and thus more likely to actually happen, that would be a good case for not having it.

          Not sure where you are getting your 100MB of thread stacks from. While threads get 512K of stack space, that is virtual memory, so just address space. Real memory is not allocated until actually needed, and it would be a very weird program that would come even close to maxing out the stack space (with deep recursion/nested call stacks + lots of local data on those deeply nested stacks) on all these I/O threads.

          And of course iOS has special APIs for doing downloads even while your app is suspended, so you should probably be using those if you’re worried about background performance.

          1. 2

            This may be true, but it doesn’t have to leak into our code. Golang has been managing just fine with m:n green threads.

            1. 1

              I do wonder why Apple didn’t design Swift that way. Maybe there are some Obj-C interop issues? I’d love a primary source on the topic.

              1. 2

                Why it was designed this way is a good question, but Objective-C interop is not the reason.

                NeXTstep used cthreads,a user-level threads package.