Как “повредиться” из dispatch_apply ()?

Есть ли способ моделировать a break оператор в a dispatch_apply() блок?

Например, каждое Какао API, я видел контакт с перечислением блоков, имеет параметр "остановки":

[array enumerateObjectsUsingBlock:^(id obj, NSUInteger i, BOOL *stop) {
    if ([obj isNotVeryNice]) {
        *stop = YES; // No more enumerating!
    } else {
        NSLog(@"%@ at %zu", obj, i);
    }
}];

Действительно ли там что-то подобно для GCD?

7
задан Michael 17 September 2011 в 00:47
поделиться

3 ответа

По замыслу dispatch _ * () API не имеют понятия отмены. Причина этого в том, что почти всегда верно, что ваш код поддерживает концепцию того, когда остановиться или нет, и, таким образом, также поддерживает то, что в диспетчере _ * () API-интерфейсы будут избыточными (а с избыточностью возникают ошибки).

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

if (is_canceled()) return;

Или:

__block BOOL keepGoing = YES;
dispatch_*(someQueue, ^{
    if (!keepGoing) return;
    if (weAreDoneNow) keepGoing = NO;
}

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

Таким образом, установка * stopFlag = YES указывает на остановку перечисления. Однако это не гарантирует немедленного прекращения работы в параллельном случае. Фактически перед остановкой перечисление может выполнить еще несколько блоков, уже поставленных в очередь.

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

14
ответ дан 6 December 2019 в 09:58
поделиться

Вы не можете нарушить dispatch_apply , поскольку это нелогично.

В -enumerateObjectsUsingBlock: разрыв четко определен, потому что функции выполняются последовательно . Но в dispatch_apply функции выполняются параллельно. Это означает, что при i = 3 -м вызове «блока» мог быть начат i = 4 -й вызов. Если вы прервите на i = 3 , должен ли вызов i = 4 по-прежнему выполняться?

@BJ - самый близкий ответ, который вы можете сделать, но всегда будут какие-то «переливы».

1
ответ дан 6 December 2019 в 09:58
поделиться

Я не думаю, что dispatch_apply поддерживает это. Лучший способ, который я могу придумать, - это создать логическую переменную __block и проверить ее в начале блока. Если он установлен, быстро спасайтесь. Вам все равно придется прогонять блок через остальные итерации, но это будет быстрее.

4
ответ дан 6 December 2019 в 09:58
поделиться