Как выполнить блок кода основного потока сразу после окончания блока кода подпотока? - PullRequest
0 голосов
/ 16 июня 2020
dispatch_queue_t queue = dispatch_queue_create("com.xxx.child", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i < 20; i++) {
    dispatch_async(queue, ^{

        NSLog(@"xxx");
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"yyy");
        });
    });
}

Надеюсь, напечатайте «xxx», «yyy», «xxx», «yyy» ...

Как изменить?

Ответы [ 2 ]

1 голос
/ 16 июня 2020

У вас есть пара проблем:

Во-первых, вы используете dispatch_async(). Эта функция ставит в очередь блок кода для выполнения асинхронно в каком-то другом потоке.

Это имеет два важных следствия:

  • Выполнение блока кода непредсказуемо ; он может выполняться до, одновременно или после остальной части кода, поставившего его в очередь.
  • Если queue - это параллельная очередь (по умолчанию), тогда остальные 19 блоков также могут выполнять одновременно; фактически, все 20 блоков могут работать одновременно, без гарантии порядка.

Чтобы гарантировать, что вы напечатаете «xxx», «yyy», «xxx», «yyy», ... вы должны убедиться, что все начальные блоки выполняются последовательно , и что каждый подблок выполняется синхронно .

Итак, ваш код должен выглядеть следующим образом:

// `queue` must be created as a serial queue
dispatch_queue_t queue = dispatch_queue_create("xxxs",DISPATCH_QUEUE_SERIAL);

for (int i = 0; i < 20; i++) {
    dispatch_async(queue, ^{

        NSLog(@"xxx");
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"yyy");
        });
    });
}

l oop немедленно создаст и поставит в очередь 20 блоков кода, добавляя их в серийный queue по порядку. Поскольку queue является последовательным, только один блок в очереди будет выполняться за раз, а второй блок в очереди не начнется, пока не завершится первый.

При выполнении первого блока он печатает «xxx» "затем синхронно ставит блок в очередь для выполнения в основном потоке. Синхронный вызов останавливает поток (первый блок) до тех пор, пока этот подблок не будет выполнен в основном потоке.

После завершения блока «yyy» вызов dispatch_sync возвращается, и первый блок возобновляет выполнение и выходы. Второй блок на queue начинает выполняться, и все это повторяется, пока не будут выполнены все блоки.

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

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
    for (int i = 0; i < 20; i++) {
        NSLog(@"xxx");
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"yyy");
        });
    }
});

Я надеюсь, что это поможет вам понять очереди и синхронные и асинхронные диспетчерские вызовы.

0 голосов
/ 25 июня 2020

Когда вы предполагаете, что не хотите видеть второй «xxx» перед тем, как увидите первый «yyy», это фактически означает, что вы действительно не хотите, чтобы они выполнялись одновременно. Определение «одновременный» заключается в том, что вы хотите, чтобы вторая задача запускалась до завершения первой (т. Е. Чтобы увидеть второй «xxx» до того, как вы увидите первое «yyy»). Единственный способ достичь строгого порядка печати «xxx», «yyy», «xxx», «yyy», ..., как указал Джеймс, - это запретить выполнение задач одновременно. И чем медленнее будут эти фоновые задачи, тем больше потеря производительности вы испытаете, если не будете запускать их одновременно. завершаются параллельные задачи; вы добьетесь более высокой производительности, чем замедление, чтобы выполнять эти задачи последовательно ». Но пока вы не дадите нам реальный пример того, что вы пытаетесь сделать, вам будет трудно что-то посоветовать.

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