skip to Main Content

In my app, I need to parse a response which is directly going to be used to render a part of the screen. The response is huge as it contains other stuff too. Since, i don’t want to do this parsing on the main thread to avoid causing issues, but I do need this response to be parsed (from gzipped format) immediately so that I can take a decision and show the expected UI quickly. In this scenario, is it ok to use
DispatchQueue.global(qos: .userInteractive // .userInitiated) to achieve this asynchronously but quickly? Is there anything I should be aware of when doing this? Any risks?

Thanks

2

Answers


  1. Is there anything I should be aware of when doing this? Any risks?

    No. This is exactly what .userInitiated means. And you’re doing it in the background, so the main thread (the interface) won’t be hampered.

    In fact, just the contrary, for best response I would recommend using a dedicated DispatchQueue you create yourself, not the global DispatchQueue, because it is concurrent and may be doing other stuff, which will slow you down.

    (Even better would be to adopt Swift Concurrency and put this work in an actor.)

    Login or Signup to reply.
  2. In short, avoid userInteractive for background work. Using userInitiated is better, and probably would be sufficient in your use-case. Even consider using default or utility. Benchmark your app and see.


    I would avoid userInteractive for this. This QoS (quality of service) is intended for work that is actually driving the UI:

    User-interactive tasks have the highest priority on the system. Use this class for tasks or queues that interact with the user or actively update your app’s user interface. For example, use this for class for animations or for tracking events interactively.

    Overuse of userInteractive for background work risks starving the main thread. Now, in your example (where you are using a single background thread and you likely have enough processors such that the UI could do its work on one processor while the background work runs on another), you probably would not manifest problems, but this is not a scalable approach. Using userInteractive for background threads is not advisable (except, of course, where it is essential, e.g., offloading calculations explicitly needed by animation of the UI, or what have you).

    Using userInitiated would be much better:

    User-initiated tasks are second only to user-interactive tasks in their priority on the system. Assign this class to tasks that provide immediate results for something the user is doing, or that would prevent the user from using your app. For example, you might use this quality-of-service class to load the content of an email that you want to display to the user.

    The userInitiated is probably fine for your use-case.


    As an aside, I must confess that, in extreme situations, when really taxing the system (e.g., using concurrentPerform to perform very intense computational tasks in parallel on all of my computer’s processors at the same time), I found that even userInitiated was sometimes too high: The UI (e.g., showing a progress indicator while the compute task was underway) was not as responsive as I would like on some hardware. Obviously, userInitiated has a lower priority than the main queue’s userInteractive QoS, and one would assume that this would ensure that the UI would not be affected, but, in practice, sometimes it is. So, I have had more consistent and responsive UI when I used default for the background work:

    Default tasks have a lower priority than user-initiated and user-interactive tasks, but a higher priority than utility and background tasks. Assign this class to tasks or queues that your app initiates or uses to perform active work on the user’s behalf.

    In my tests (in massively parallel compute tasks, at least), the overall performance of default was not observably different than userInitiated, but default ensured a smoother UI. (As an aside, people frequently over-estimate the performance impact of one QoS over another and neglect to benchmark performance to validate their assumptions.)

    Bottom line, I would advise benchmarking default (or even utility) against userInitiated for your use-case, and see if there is any consistent, observable difference. Since you are only using one background thread, it probably does not matter, but if doing something more intensive, even .userInitiated might be too high of a QoS.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search