代码之家  ›  专栏  ›  技术社区  ›  Coocoo4Cocoa

iPhone应用程序中的异步vs同步vs线程

  •  26
  • Coocoo4Cocoa  · 技术社区  · 16 年前

    我正在为一个将使用RESTWeb服务的应用程序设计阶段,在使用异步vs同步vs线程方面有点进退两难。下面是场景。

    假设您有三个选项可以钻取,每个选项都有自己的基于REST的资源。我可以用同步请求惰性地加载每个请求,但这样会阻塞UI,并防止用户在检索数据时点击后退导航按钮。这种情况几乎适用于任何地方 除了 当应用程序需要登录屏幕时。我看不到使用同步HTTP请求与异步HTTP请求的任何原因,因为仅此一个原因。唯一有意义的时间是让工作线程发出同步请求,并在请求完成时通知主线程。这将阻止阻塞。然后,问题是对代码进行基准测试,看看哪个开销更大,是线程同步请求还是异步请求。

    异步请求的问题是,您需要设置智能通知或委派系统,因为您可以在任何给定时间对多个资源进行多个请求。它们的另一个问题是,如果我有一个类(比如处理所有数据的单例类),我就不能在getter方法中使用异步请求。这意味着以下情况不会发生:

     - (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;
     }
    

    你也可能有优先权。我所说的优先级是,如果你在iPhone上查看苹果的邮件应用程序,你会发现它们首先会吸走你的整个pop/imap树,然后再发出第二个请求来检索你邮件的前2行(默认)。

    我想我的问题是专家们。什么时候使用异步、同步、线程——什么时候在线程中使用异步/同步?当异步请求完成时,您有什么样的委托系统来知道要做什么?您是否对异步请求进行优先级排序?

    对于这个太普遍的问题,有各种各样的解决办法。很容易破解出一些东西。问题是,我不想黑客,我想要一些简单易维护的东西。

    8 回复  |  直到 13 年前
        1
  •  7
  •   Stephen Darlington    16 年前

    我认为没有“正确”的答案。似乎你理解其中的妥协,你只需要围绕这些做你的设计。

    一些额外的随机点:有时应用程序强制使用特定的方法。例如,许多方便(即同步)的方法不允许进行身份验证。对我来说,这意味着我的决定已经做出了。

    为了 Yummy 我结束了 使用线程。我的所有网络调用都是异步的,并且使用了默认的XML解析器(它使用回调进行工作)。因为它都是事件驱动的,而且每个单元都很小,所以它允许GUI非常流畅,而不需要复杂的线程处理。

    我使用状态机来弄清楚为什么我得到一个特定的响应,以及一个队列,这样我在任何给定的时间都只需要进行一次“飞行中”的操作。大多数请求都有不同的顺序,所以我不需要优先级系统。

    网络代码在我的应用程序中是最复杂的,它花了很长时间才变得不那么健壮!

        2
  •  8
  •   Marc Charbonneau    16 年前

    我不会对异步委托调用打折,但我通常最终会使用带有同步请求的线程工作类。我发现,从长远来看,拥有一个定义良好的线程化API要容易得多,而不是用管理异步方法之间状态的代码填充控制器。您甚至可以在工作线程中实现异步,尽管通常使用同步方法更容易,除非它们不支持您需要使用的特性。当然,所有这些都取决于环境,我可以想到许多情况,其中简单地使用异步方法将是最好的路由。

    如果您走这条路线,一定要考虑nsOperationQueue;它大大简化了创建多个工作线程,并且它还支持操作之间的优先级和依赖性。现在10.5版有一些问题,但我没有听说iPhone有任何问题。

        3
  •  8
  •   bbrown    16 年前

    官方答复是你应该 almost always go asynchronous synchronous is bad . 我发现 ASIHTTPRequest 使异步请求变得简单。

        4
  •  1
  •   Mitchel Sellers    16 年前

    我亲自查看正在执行的操作,通常会使用asyc请求来确保UI不会阻塞,但是,在请求过程中,我可能会禁用应用程序的UI。

    这方面的一个主要例子是在我用“搜索”按钮构建的应用程序中。一旦搜索被触发为异步请求,我将禁用该按钮,直到响应返回,有效地限制了用户生成第二个asyc请求的能力。

    这样做,至少我可以防止优先级的需要,如果你能以一种简单的方式,限制你的用户一次只能执行一个操作,那么这就行了。

        5
  •  1
  •   August    16 年前

    毫无疑问,我建议采用不对称的方式。然后,仅在需要时加载信息,并使用委托系统将该信息提供给正确的对象。

    您不想阻止用户界面。永远。异步加载信息可以让您更好地控制正在发生的事情,以便在需要时抛出错误消息。

        6
  •  1
  •   Thomas Tempelmann    15 年前

    只是一个想法:如果你想使用iPhone的单元测试框架,你可以 可以 希望具有同步功能,因为这样可以使编写测试更加容易。

    但是,有些API可能无法同步工作,因此需要将它们转换为同步任务。如果执行单元测试的代码在其自己的线程中运行,则可以编写一个包装器,等待异步任务完成。

    为了实现这一点,您需要使用一个信号量:包装器函数启动异步操作,然后使用该信号量来阻塞自己(即使自己进入睡眠状态)。发出异步事件结束信号的回调释放信号量,以便休眠包装线程可以继续并返回。

        7
  •  0
  •   Nate Symer    13 年前

    我将使用带有同步的分派异步。这样,您就可以不使用委托/nsnotifications,而且不会阻塞

    - (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;
               }
         }
    }
    
        8
  •  -1
  •   Kendall Helmstetter Gelner    16 年前

    为什么不能使用这样的异步请求:

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

    异步绝对是唯一的选择——唯一真正的问题是,您是想开始使用单独的线程,还是只想使用异步调用。从那里开始,如果您真的需要的话,看看管理线程。