Почему блок синхронизации всегда вызывает основной поток?

Я провел простой тест с DispatchQueue:

DispatchQueue.global(qos: .background).sync {
  if Thread.isMainThread {
    print("Main thread")
  }
}

Распечатано:

Main thread

Почему этот код выполняется в основном потоке? Это должно выполняться в фоновом потоке (он был добавлен в фоновую очередь), верно?


person Cuong Vuong    schedule 23.10.2018    source источник
comment
Из документации функции sync: В целях оптимизации эта функция по возможности вызывает блок в текущем потоке.   -  person dan    schedule 23.10.2018
comment
Не путайте очереди и потоки. Работайте с очередями и позвольте им беспокоиться о потоках за вас!   -  person matt    schedule 23.10.2018


Ответы (2)


Потому что на самом деле это не обязательно. Вы блокируете основной поток с помощью синхронизации. iOS предпочитает просто выполнять его в основном потоке, вместо того, чтобы беспокоиться о переключении на фоновый поток (фоновой очереди), поскольку это не имеет особого значения из-за того, что основной поток все равно заблокирован.

В документации Apple (и быстрой помощи) по функции синхронизации есть строка:

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

person Smartcat    schedule 23.10.2018

Проблема в том, что вы задали неправильный вопрос. Не путайте очереди и потоки. Работайте с очередями и позвольте им перенаправить потоки по мере необходимости. Именно поэтому у нас есть очереди! Вам не нужно беспокоиться о том, в ветке вы находитесь. Все, что вам нужно знать, это то, что вы находитесь в нужной очереди, которую вы можете узнать следующим образом:

let q = DispatchQueue.global(qos: .background)
q.sync {
    dispatchPrecondition(condition: .onQueue(q))
    print("it's okay! we're on the right queue") // yep
}
person matt    schedule 23.10.2018
comment
Привет, спасибо за информацию. Я просто хочу больше разбираться в очередях и потоках! Я почти уверен, что меня это не смущает, но все же задаюсь вопросом, почему этот блок произошел в основном потоке. Думаю, оптимизация - приемлемый ответ. - person Cuong Vuong; 23.10.2018
comment
@Matt Маргинальный вопрос, но есть ли лучший способ, как это сделать? pastebin.com/R5KeWrjY - person Alexander; 23.10.2018
comment
@Alexander Это, вероятно, наилучшая практика, насколько это возможно (stackoverflow.com/questions/10330679/), но еще лучше спросить себя, действительно ли вам нужно звонить main.sync в первую очередь. - person matt; 23.10.2018
comment
Да, если вы хотите, чтобы работа выполнялась в фоновой очереди, напишите свой код так, чтобы ваша основная очередь могла начать работу в этой фоновой очереди, а затем продолжить работу, а затем ваш основной код очереди может быть уведомлен во время следующего цикла доходности каким-либо образом ( например, через закрытие завершения, вызываемое в основной очереди), когда работа завершена в фоновой очереди. - person Smartcat; 23.10.2018
comment
@matt В моем конкретном случае это был вызов reloadData() в представлениях таблицы представлений, управляемых моим VC. Существует несколько контекстов, в которых была необходима перезагрузка данных. Некоторые были в основном потоке (часть @IBActions), а некоторые - вне основного потока (асинхронный код rx). - person Alexander; 23.10.2018
comment
@Alexander Что сказал Smartcat. Вся ваша архитектура была неправильной. Давайте отбросим эту цепочку комментариев; если вы хотите задать вопрос об этом, пожалуйста, сделайте это! - person matt; 23.10.2018