почему concurrentQueue.sync НЕ вызывает тупик - PullRequest
0 голосов
/ 14 ноября 2018

Этот код заблокирован, потому что:

  1. они в одной теме
  2. print (2) должен ждать print (3)
  3. print (3) должен ждать print (2)

Например:

DispatchQueue.main.async {
    print(Thread.current)
    DispatchQueue.main.sync {
        print(Thread.current)
        print(2)
    }
    print(3)
}

Почему в concurrentQueue не возникнет тупик? Они тоже в одной теме.

DispatchQueue.global().async {
    print(Thread.current)
    DispatchQueue.global().sync {
        print(Thread.current)
        print(2)
    }
    print(3)
}

1 Ответ

0 голосов
/ 22 декабря 2018

Вы спрашиваете:

Почему в concurrentQueue не возникнет тупик?Они также находятся в одной теме.

Нет, они обязательно находятся в одной теме.Они находятся в той же очереди , , но не обязательно в том же потоке . (В рамках оптимизации, см. Ниже, на самом деле он может работать в том же потоке, но необязательно так. Но логически вы должны думать о том, что он работает в отдельном потоке.)

В этом и заключается вся идея "параллельных очередей", заключающаяся в том, что они могут запускать отдельные отправленные задачи в разных потоках.Вот как они разрешают одновременную работу.Одна отправленная задача в параллельной очереди может выполняться в одном потоке, а другая отправленная задача в той же очереди может выполняться в отдельном потоке.

Как указывает старое Руководство по программированию параллелизма в своем определении «параллельной очереди»:

Выполняемые в настоящее время задачи выполняются в отдельных потоках, которые управляютсяочередь отправки.

Или, как сказано в документации DispatchQueue , :

DispatchQueue управляет выполнением рабочих элементов.Каждый рабочий элемент, отправленный в очередь, обрабатывается в пуле потоков , управляемых системой.[выделение добавлено]


Что немного запутывает, так это то, что существует оптимизация GCD, которая, если вы отправляете синхронно ...

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

Таким образом, при синхронной диспетчеризации из очереди фактически может в конечном итоге этот код выполняется в том же потоке (если только вы не отправляете из фоновой очереди в основную очередь).Обратите внимание:

let queue = DispatchQueue.global()
let queue2 = DispatchQueue(label: "queue2")

queue.async {
    print(1, Thread.current)
    queue2.sync {
        print(2, Thread.current)
    }
    print(3, Thread.current)
}

Этот второй оператор print покажет, что даже если у вас совершенно другая очередь, он может, как часть вышеупомянутой оптимизации sync, запустить код в текущем потоке.То же самое верно, если этот внутренний sync вызов был к тому же queue, к которому был отправлен внешний блок.

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

Но одновременная отправка очереди в саму себя не является тупиковой, хотя из-за этой оптимизации sync может закончиться выполнение кода в том же потоке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...