Что произойдет, если отправка в той же очереди? - PullRequest
0 голосов
/ 29 октября 2019

Я хотел бы понять, для случая ниже, нужно ли проверить, является ли callbackQueue текущей очередью.

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

  1. callbackQueue - главная очередь.
  2. callbackQueue - одновременная очередь.
  3. callbackQueue - последовательная очередь,
- (void)fetchWithCallbackQueue:(dispatch_queue_t)callbackQueue
{
  dispatch_async(callbackQueue, ^{

  });
}

Ответы [ 2 ]

1 голос
/ 29 октября 2019

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

Если, однако, вы использовали dispatch_sync (он же sync)в Swift), то внезапно возникают проблемы, если вы отправляете очередь из последовательного порта обратно в себя. При «синхронной» отправке из последовательной очереди в себя код будет «тупиковым». (И поскольку основная очередь представляет собой последовательную очередь, синхронные отправки из основной очереди в себя проявляют ту же проблему.) dispatch_sync говорит «заблокировать текущий поток, пока назначенная очередь не завершит выполнение этого отправленного кода», поэтому, очевидно, если какой-либо последовательныйочередь отправляется синхронно обратно к себе, она не может продолжаться, потому что она блокирует очередь, в которую вы отправили код для запуска.

Обратите внимание, что любой блокирующий GCD API, такой как dispatch_semaphore_waitи dispatch_group_wait (оба в Swift называются просто wait) будут страдать от той же проблемы, что и синхронная диспетчеризация, если вы ожидаете в том же потоке, который использует последовательная очередь.

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

1 голос
/ 29 октября 2019

Я настоятельно рекомендую вам посмотреть эти видео. Затем просмотрите примеры, которые я предоставил, а затем измените код и поиграйте с ними столько, сколько сможете. Мне потребовалось 3 года, чтобы полностью освоиться с многопоточностью iOS, поэтому не торопитесь: D

Посмотрите первые 3 минуты этого видео RWDevCon и более, если хотите.

Также смотрите 3: 45 до 6: 15 . Хотя я рекомендую вам посмотреть это видео полностью.


Подводя итог тем моментам, о которых говорилось в видео, за упомянутую мною продолжительность:

многопоточность и параллелизм относятся к очереди source и destination . очередь.

синхронизация и асинхронность, в частности, зависит от очереди источника.

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

Если вы выполните async , то вы как бы отправляете машину (должна доставить вещи), выезжая с шоссе, а затем продолжаете позволять другим машинам двигаться по шоссе.

Если вы выполните sync , то вы как бы отправляете машину (должна доставить вещи) с шоссе и затем прекращаете позволять любой машине продолжать, пока машина не доставит все свои вещи.

Думайте об автомобиле, который доставляет вещи как блок кода, начиная и заканчивая выполнением.


То, что происходит для основной очереди, идентично тому, что происходит для последовательной очереди. Они обе последовательные очереди.

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

Чтобы показатьВы, что я имею в виду: в каком порядке, как вы думаете, это будет печатать? Вы можете легко проверить это на игровой площадке:

DispatchQueue.main.async {
    print("1")
    print("2")
    print("3")
    DispatchQueue.main.async {
        DispatchQueue.main.async {
            print("4")
        }
        print("5")
        print("6")
        print("7")
    }
    print("8")
}

DispatchQueue.main.async {
    print("9")
    print("10")
}

Будет напечатано:

1
2
3
8
9
10
5
6
7
4

Почему?

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

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


Что произойдет, если вы отправите в ту же очередь serial , используя sync ?

Deadlock! См. здесь

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


Теперь, если вы пытаетесь отправить в параллельную очередь, тогда, если вы делаете sync , это похоже на пример шоссе,где вся 5-полосная магистраль заблокирована, пока машина не доставит все. Но синхронизировать в параллельной очереди довольно бесполезно, если только вы не делаете что-то вроде .barrier очереди и не пытаетесь решить проблему read-write .

Но чтобы увидеть, что произойдет, если вы выполните синхронизацию в параллельной очереди:

let queue = DispatchQueue(label: "aConcurrentQueue", attributes: .concurrent)

for i in 0...4 {
    if i == 3 {
        queue.sync {
            someOperation(iteration: UInt32(i))
        }
    } else {
        queue.async {
            someOperation(iteration: UInt32(i))
        }
    }
}

func someOperation(iteration: UInt32) {
    sleep(1)
    print("iteration", iteration)
}

запишет:

// '3' will ALWAYS be first, because it's chocking the entire queue. 
// The rest happen concurrently. And each time you run the app, the sequence of the rest would be different, because of the nature of concurrency. But likely 4 will be closer to being completed last and 0 would be closer to being finished sooner.

iteration 3     
iteration 0
iteration 2
iteration 1
iteration 4

Если вы выполните async напараллельная очередь, тогда предположим, что у вас есть ограниченное количество одновременных потоков, например, 5, то 5 задач будут выполняться одновременно. Просто каждая заданная задача идет в конец очереди. Было бы целесообразно сделать это для ведения журнала. Вы можете иметь несколько тем журнала. Один поток регистрирует события местоположения, другой регистрирует покупки и т. Д.

Хорошим примером игровой площадки будет:

let queue = DispatchQueue(label: "serial", attributes: .concurrent)

func delay(seconds: UInt32 ) {
    queue.async {
        sleep(seconds)
        print(seconds)
    }
}

for i in (1...5).reversed() {
    delay(seconds: UInt32(i))
}

Даже если вы сначала отправили 5, это вывело бы

1
2
3
4
5
...