执行同步任务的最常见和最正确的模式,即创建复合操作的异步任务

时间:2012-10-21 21:42:04

标签: objective-c design-patterns asynchronous

我是iOS和Objective-C的新手。

我正在开发一个项目,旨在尽可能简化复杂(或“复合”)操作的组合:https://github.com/stanislaw/SACompositeOperations

我在那里有四种操作:两种单一操作(同步和异步)和两种复杂操作(级联和“事务”)。单个操作被用作复杂操作的“原子”,因此我希望尽可能地使它们符合Objective-C最佳实践。

我感兴趣的是:我应该为这些单一操作选择哪些代码

通过调用两个单个操作中的第一个“sync”,我的意思是:运行一些可能与完成处理程序异步的东西并锁定流程等待它完成。 “异步”意味着真正的异步操作 - 只需以异步方式运行操作块。

以下是我目前使用的单个操作代码:

同步操作

- (void)run:(syncOperationBlock)block {
    self.semaphore = dispatch_semaphore_create(0);

    block(self);

    while (dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_NOW))
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                                                       beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]];
}

- (void)finish {
    dispatch_semaphore_signal(self.semaphore);
}

@end

异步操作

- (void)run:(asyncOperationBlock)block {
    dispatch_queue_t queue = dispatch_queue_create("async_operation.queue", 0);

    dispatch_async(queue, ^{
        block(self);
    });
}

如果有人可以为这些单同步和异步操作建议任何解决方案,我将感激不尽:更通用更常见更好< / em>对于我所描述的案例

简而言之:对于异步操作,强制同步操作的最佳代码是什么?

感谢。

1 个答案:

答案 0 :(得分:0)

自从我提出这个问题以来,我的项目确实发生了很大变化。

从结构的角度来看,我不能说异步操作很有趣:在我的项目中,它们都基于dispatch_async,最有价值的功能是通过密集使用块来实现的(主要是:将操作本身放到了他们执行的块,允许控制这些操作的流程。)

这里要注意的更有趣的是我目前用于同步(或“强制同步”)操作的代码 - 尽管在真实应用程序中应避免使用它们,但它们仍然适用于单元测试:一个例子是在单元测试用例的上下文中,需要理顺异步网络请求的卷曲异步流以测试其结果。

虽然我发布这个作为我的非特定问题的答案,但我仍然希望看到任何关于我的SASyncOperation是否足以用于强制同步操作的权威性答案(在某种意义上我已经在此描述了它)问题)或者可能会进一步改进。

目前正在编写

SASyncOperation

  • 如果主线程在主线程上运行,则不阻塞主线程。
  • 使用进行简单的方法时不会产生过多的CPU轮询(!!completed){};

这是代码中最重要的部分:

#import "SASyncOperation.h"

@interface SASyncOperation () {
    BOOL _isOnMainThread;
    dispatch_semaphore_t _semaphore;
}
@end

@implementation SASyncOperation

// …

- (void)start {
    _semaphore = dispatch_semaphore_create(0);

    _operation(self);

    if (_finished) return;

    if ((_isOnMainThread = [NSThread isMainThread])) {
        while (dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_NOW)) {
            CFRunLoopRunInMode(kCFRunLoopDefaultMode, [[NSDate distantFuture] timeIntervalSinceNow], NO);
        }
    } else {
        dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);
    }

    _finished = YES;
}

- (void)run:(^(void)(SASyncOperation *)block {
    _operation = [block copy];

    [self start];
}

- (void)finish {
    _finished = YES;

    dispatch_semaphore_signal(_semaphore);

    if (_isOnMainThread) {
        dispatch_async(dispatch_get_main_queue(), ^{
            CFRunLoopStop(CFRunLoopGetMain());
        });
    }
}

// …
@end

这就是SASyncOperation的使用方式:

SASyncOperation *syncOperation = [[SASyncOperation alloc] init];

[syncOperation run:^(SASyncOperation *so) {
    doSomeThingMultiQueuedPossiblyMultiblockedAndAsynchronous(^{
        soOver = YES;
        [so finish];
    });
}]; // <- (*)

// (*) The flow will be stopped at this point waiting when 'so' operation will finish itself