Swift Concurrency – почему моя задача не унаследовала исполнителя и приоритет родительской задачи

Создавая задачу A из задачи B, я думал, что задача A унаследует задачу B. Но при запуске следующего кода, который я создал, почему строка 14 была напечатана debug 4: <NSThread: 0x30361a300>{number = 6, name = (null)}. Почему это не основная нить, как и другие гравюры?

Вот код для тех, кто хочет запустить локально:

struct Test {
    func test() {
        print("debug 3:", Thread.current)
        Task {
            print("debug 4:", Thread.current)
        }
    }
}

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        Task { @MainActor in
            print("debug 1:", Thread.current)
            Task {
                print("debug 2:", Thread.current)
                Test().test()
            }
        }
    }
}
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
57
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Функция test не изолирована от актера. Таким образом, его Task {…} также не изолирован от актера. (Если бы test был изолирован от актера, то его Task {…} была бы задачей верхнего уровня для того же актера. Но test не был изолирован от актера, так что это спорный вопрос.)

В параллелизме Swift изоляция функции либо определяется явно, либо наследуется от типа, в котором она определена, если таковой имеется, но она не «наследует» ее от вызывающей стороны.

Спасибо @Роб! Как бы я отметил эту функцию как изолированного актера?

Shuaiqing Luo 02.08.2024 18:15

Теоретически вы могли бы просто добавить к определению функции глобальный квалификатор актера, например, @MainActor func test() {…}. Но немного странно иметь изолированную функцию в struct, потому что это тип значения (с помощью которого мы обычно достигаем потокобезопасности, просто предоставляя каждому потоку свою собственную копию). Вероятно, нам нужно увидеть практический пример того, что вы пытаетесь сделать в test, чтобы дать вам дальнейшие советы. Я также мог бы отослать вас к stackoverflow.com/a/76868102/1271826, который, рассматривая другой вопрос, иллюстрирует как безопасное, так и небезопасное взаимодействие с struct.

Rob 03.08.2024 18:43

Спасибо @Rob, да, это имеет смысл. Я также опубликовал ответ, основанный на вашем. Дайте мне знать, если что-то не так, спасибо!

Shuaiqing Luo 03.08.2024 22:27

Я привел несколько дополнительных примеров для объяснения ответа @Rob.

  • Пример 1:

    • Поскольку test() — это nonisolated, он будет использовать фоновый поток, поэтому debug 3 печатает поток bg. Задача, созданная в строке 13, является задачей верхнего уровня и не привязана ни к какому актеру, поэтому в этом случае она использовала случайный поток bg.
  • Пример 2:

    • UIViewController использует MainActor, поэтому и debug 3, и debug 4 выполняются в основном потоке, поскольку test() — это функция класса MainActor.
  • Пример 3:

    • Как и в примере 1, debug 3 и debug 4 будут использовать поток bg, потому что test() — это функция nonisolated, даже если она находится в классе MainActor.

Вместо «случайного фонового потока» можно отметить поток из «совместного пула потоков» (которого, кстати, следует избегать блокировки, поскольку этот пул ограничен количеством ядер вашего устройства).

Rob 03.08.2024 22:57

Обратите внимание, что в Task {…} в viewDidLoad@MainActor in является избыточным. UViewController изолирован от главного актера, как и его методы в вашем подклассе, поэтому Task уже изолирован от главного актера.

Rob 03.08.2024 23:07

Спасибо за заметки! Да, @MainActor является избыточным, я добавил его только для того, чтобы было ясно, что это в MainActor.

Shuaiqing Luo 03.08.2024 23:32

Другие вопросы по теме