【问题标题】:@synchronized (self) - best way@synchronized (self) - 最好的方法
【发布时间】:2016-07-05 10:32:38
【问题描述】:

我目前已经开始研究 @synchronized 的工作原理,以及它如何锁定对象。

@synchronized(self) {
    [self getDataWithCompletionBlock:^{
        dispatch_async(dispatch_get_main_queue(), ^{
            [refreshControl endRefreshing];
            [self.collectionView reloadData];
            loadingView.hidden = YES;
            self.oneTimeCallReach = NO;
        });
    }];
}

这完全错了吗?

【问题讨论】:

  • 可能吗?在不知道自己要做什么的情况下,很难说是否有问题。这只会在getDataWithCompletionBlock 调用返回之前锁定,在异步调用返回之前不会锁定。

标签: ios synchronization synchronized


【解决方案1】:

我假设您在 getDataWithCompletionBlock 中异步更新一些模型对象。不幸的是,您发布的代码不会同步异步更新。这些更新和您的完成块本身都不会与该代码同步。

假设您要同步异步检索的数据,您应该:

  • 删除包装方法调用的同步指令;

  • 不要更新方法内的模型对象;

  • 相反,只需将其检索到一个局部变量,然后您将一个附加参数传递回完成块;

  • 然后,在您的完成块中,使用传递给块的参数执行模型更新,并根据需要进行同步。

顺便说一句,如果您将模型的更新分派到主队列,您可以完全退出 synchronized 指令,而是使用主线程来同步所有更新。 (调度更新和对串行队列的访问是同步多个线程访问的完全可接受的方式,主队列本身就是一个串行队列。)如果对模型的所有读取和写入都发生在主线程上,则实现必要的同步。但是,显然,如果您从其他线程访问模型,那么您将需要同步它。但通常将对模型的访问限制在主线程是一种不错的简单同步机制。正如苹果在他们的Concurrency Programming Guide 中所说:

完全避免同步

对于您从事的任何新项目,甚至对于现有项目,设计代码和数据结构以避免需要同步是最好的解决方案。尽管锁和其他同步工具很有用,但它们确实会影响任何应用程序的性能。如果整体设计导致特定资源之间的高争用,您的线程可能会等待更长的时间。

实现并发的最佳方式是减少并发任务之间的交互和相互依赖。如果每个任务都对自己的私有数据集进行操作,则不需要使用锁来保护该数据。即使在两个任务确实共享一个公共数据集的情况下,您也可以查看对该数据集进行分区或为每个任务提供其自己的副本的方法。当然,复制数据集也有其成本,因此您必须在做出决定之前权衡这些成本与同步成本。

无论如何,如果你想尽量减少他需要同步自己,它可能看起来像:

[self getDataWithCompletionBlock:^(NSArray *results){
    dispatch_async(dispatch_get_main_queue(), ^{
        self.objects = results;
        [refreshControl endRefreshing];
        [self.collectionView reloadData];
        loadingView.hidden = YES;
        self.oneTimeCallReach = NO;
    });
}];

现在,很明显,我不知道你的模型是什么,所以我的NSArray 示例可能不正确,但希望这能说明这个想法。让完成处理程序负责同步更新(如果您没有任何其他线程直接访问模型,则使用主队列来同步访问)。

就个人而言,我可能还包含一些错误参数,以便更新 UI 的块可以检测和处理可能发生的任何错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-21
    • 1970-01-01
    • 2011-06-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多