асинхронная функция swift выполняется в основном потоке в некоторых случаях при запуске из задачи

#swift #swiftui #swift5.5 #swift-concurrency

Вопрос:

В этом случае асинхронная функция считывает файл и возвращает проанализированное содержимое.

На мой взгляд, я хочу загрузить содержимое из основного потока, а затем обновить представление после завершения.

Я использовал этот шаблон в разных местах и заметил, что в некоторых случаях асинхронный вызов выполняется в основном потоке (путем отладки), а в других — в Thread 4 Queue : com.apple.root.user-initiated-qos.cooperative (concurrent) потоке

Например:

 struct MyView: View {
  @State var data = "some data"
  var body: some View {
    Button("refresh") {
    // when the button is pressed refresh it
            Task {
                await refresh()
            }
        }.task {
    // when the view appears
            await refresh()
        }
     Text("the data is (data)") // write the data which was refreshed async
   }


  }
  func refresh() async {
        do {
            let res = try await anotherAyncFunction()
            data = res // this is presumably wrong and off the main thread - obviously might not be correct but leave here for debug as well
        } catch {
            print("got error (error)")
        }
    }
 

Я создал несколько разных представлений, используя аналогичный шаблон ( .task async функции вызова блоков)

В некоторых случаях функции выполняются долго (чтение с диска), и это происходит в основном потоке

Комментарии:

1. Вам может понравиться видео Swift concurrency: за кулисами , в котором рассказывается о том, как Swift Concurrency планирует задачи.

Ответ №1:

Измените Task { на Task.detached { .

Из руководства по языку Swift:

Чтобы создать неструктурированную задачу, которая выполняется на текущем исполнителе, вызовите Task.init(priority:operation:) инициализатор. Чтобы создать неструктурированную задачу, которая не является частью текущего участника, более конкретно известную как отдельная задача, вызовите метод Task.detached(priority:operation:) класса.

При вызове Task.init асинхронный код выполняется для текущего участника, который в данном контексте является основным участником. Это приводит к блокировке основного потока.

Вызывая Task.detached , вы позволяете асинхронной работе выполняться вне основного потока.

Комментарии:

1. Не работает, мой Task отсоединен, но он находится в основном потоке.

Ответ №2:

Используя структурированный параллелизм Swift, для запуска кода в фоновом потоке используйте отдельную задачу или (лучше) субъекта.