Асинхронный и синхронный против потоков в приложении для iPhone - PullRequest
26 голосов
/ 16 декабря 2008

Я нахожусь в стадии разработки для приложения, которое будет использовать веб-сервис REST и, в некотором роде, сталкивается с дилеммой в том, что касается использования асинхронного и синхронного потоков, а также потоков. Вот сценарий.

Допустим, у вас есть три варианта, каждый из которых имеет собственный ресурс на основе REST. Я могу либо лениво загрузить каждый из них с синхронным запросом, но это заблокирует пользовательский интерфейс и не даст пользователю нажать кнопку обратной навигации, пока данные извлекаются. Этот случай применяется почти везде , за исключением , когда вашему приложению требуется экран входа. Я не вижу никакой причины использовать синхронные HTTP-запросы против асинхронных по одной только этой причине. Единственный раз, когда это имеет смысл, - это чтобы рабочий поток сделал ваш синхронный запрос и уведомил основной поток о завершении запроса. Это предотвратит блокировку. Тогда вопрос заключается в том, чтобы разметить ваш код и увидеть, у кого больше накладных расходов, многопоточный синхронный запрос или асинхронный запрос.

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

 - (NSArray *)users {
     if(users == nil)
        users = do_async_request // NO GOOD

     return users;
 }

, тогда как следующее:

 - (NSArray *)users {
    if(users == nil)
      users == do_sync_request // OK.

    return users;
 }

Вы также можете иметь приоритет. Под приоритетом я подразумеваю, что если вы посмотрите на приложение Apple Mail на iPhone, вы заметите, что они сначала высасывают все ваше дерево POP / IMAP, а затем делают второй запрос на получение первых двух строк (по умолчанию) вашего сообщения.

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

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

Ответы [ 8 ]

8 голосов
/ 21 мая 2009

Официальный ответ таков: почти всегда должен работать асинхронно , а синхронно - плохо . Я обнаружил, ASIHTTPRequest упрощает асинхронные запросы.

8 голосов
/ 19 декабря 2008

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

Обязательно рассмотрите NSOperationQueue, если вы идете по этому маршруту; это значительно упрощает создание нескольких рабочих потоков, а также поддерживает приоритеты и зависимости между операциями. Сейчас на 10.5 есть некоторые проблемы с ним, но я не слышал о каких-либо проблемах с iPhone.

7 голосов
/ 16 декабря 2008

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

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

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

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

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

1 голос
/ 11 апреля 2010

Просто мысль: если вы хотите использовать платформу Unit Testing для iPhone, вы можете захотеть иметь синхронную функциональность, поскольку это может упростить написание тестов.

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

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

1 голос
/ 16 декабря 2008

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

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

1 голос
/ 16 декабря 2008

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

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

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

0 голосов
/ 28 августа 2012

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

- (NSArray *)users {
    if(users == nil) {
        users = do_sync_request();
    }

    return users;
}

// now when calling the users method, do this

- (NSArray *)getUsers {
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
           NSArray *users = [self users];
           dispatch_sync(dispatch_get_main_queue(), ^{
                 return users;
           }
     }
}
0 голосов
/ 17 декабря 2008

Почему вы не можете использовать асинхронный запрос следующим образом:

- (NSArray *)users {
     if(users == nil && !didLaunchRequestAlready )
        users = do_async_request // Looks good to me
     return users;
 }

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

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