В чем разница между синхронными и асинхронными вызовами в Objective-C и многопоточностью?

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

однако с тех пор мне стало известно, что вы можете совершать асинхронные вызовы на основном thread и синхронные вызовы фоновых потоков.

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

7 ответов


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

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

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

// one of the global concurrent background queues

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

// or you could create your own serial background queue:
//
// dispatch_queue_t queue = dispatch_queue_create("com.domain.app.queuename", 0);

во-вторых, вы отправляете свои задачи в эту очередь асинхронно:

dispatch_async(queue, ^{
    // the slow stuff to be done in the background
});

шаблон для очередей операций очень похож. Создать operation queue и добавление операций в эту очередь.

на самом деле синхронное и асинхронное различие полностью отличается от различия основной очереди и фоновой очереди. Но когда люди говорят о" запустить какой-то медленный процесс асинхронно", они действительно говорят " запустить какой-то медленный процесс асинхронно в фоновой очереди."


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

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

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

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

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


давайте возьмем несколько простых примеров :

асинхронный вызов с многопоточностью :

// Methods gets called in different thread and does not block the current thread. 
[NSURLConnection sendAsynchronousRequest:request 
                                   queue:queue 
                       completionHandler:
    ^(NSURLResponse *response, NSData *data, NSError *error) {
}];

синхронный вызов с многопоточностью:

//Do something
dispatch_sync(queue, ^{
    //Do something else
});
//Do More Stuff

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

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

следовательно, dispatch_sync редко используется. Но она есть. Лично я никогда этим не пользовался. Почему бы не запросить пример кода или проекта, который использует dispatch_sync.

асинхронный вызов с одним потоком:

[self performSelector:@selector(doSomething) withObject:nil afterDelay:0];

здесь текущий runloop для завершения перед вызовом "doSomething". Другими словами, текущий стек вызовов может быть завершен ( текущий метод возвращает) перед вызовом' doSomething'.

синхронный вызов с одним потоком:

 [self doSomething];

Я не думаю, что вам нужно объяснение для этого.

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


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

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

но если вы позвонили dispatch_async фоновый поток будет продолжаться с остальной частью указанного кода, и основной поток будет запускать запрошенный dispatch заблокировать.

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

всякий раз, когда у вас есть код расчета, код webservice, выборка кода, что не влияет на пользовательский интерфейс лучше всего сделать это в отдельном потоке. Для такого рода вещей я бы сделал dispatch_async в глобальный поток. Затем, когда этот код будет завершен, я бы запустил dispatch_async назад в основной поток, чтобы сказать ему обновить пользовательский интерфейс с тем, что я только что рассчитал.

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


Это обсуждение в значительной степени отвечает на него: асинхронный vs многопоточный-есть ли разница?

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

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

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


swift 3, 4, 4,2 синхронно означает, что поток, инициировавший эту операцию, будет ждать завершения задачи, прежде чем продолжить.

DispatchQueue.main.sync {

}

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

DispatchQueue.main.async {

}

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

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