我正在尝试在后台线程上按顺序完成一些操作。
我调用的函数已经有一个完成块,所以当函数完成时我想用一个新参数调用相同的函数。
所以基本上是连续的操作。
dispatch_async
或DISPATCH_QUEUE_SERIAL
以正确的顺序触发函数,但在调用下一个函数之前不关心第一个函数是否完成,所以我不想使用它们。
NSOperationQueue* serialQ = [[NSOperationQueue alloc] init];
serialQ.maxConcurrentOperationCount = 1;
对我更有意义。因此,当第一个函数开始计算队列上的第二个函数时,必须等到它完成完成块。
NSOperationQueue* serialQ = [[NSOperationQueue alloc] init];
serialQ.maxConcurrentOperationCount = 1; //this will set this queue to Serial
for (File *file in queueArrray) {
Streamer *streamer=[[Streamer alloc] init];
NSBlockOperation *downloadOperation = [[NSBlockOperation alloc] init];
__weak NSBlockOperation *weakDownloadOperation = downloadOperation;
[weakDownloadOperation addExecutionBlock:^{
[streamer loadFile:file withCallback:^(NSString *error, BOOL success) {
if (success) {
NSLog(@"file loaded %@",file.fileUrl);
//here start the next operation !!!!!!!!
??????????????????????????????????????
}
}];
}];
}
答案 0 :(得分:3)
串行队列infact确保添加到要执行的队列的第一个块在第二个块执行之前完成。
-(void)testSerialQueue
{
dispatch_queue_t serialQueue = dispatch_queue_create("com.serial.queue", DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQueue, ^{
[self countTo100];
});
dispatch_async(serialQueue, ^{
[self countFrom200To400];
});
dispatch_async(serialQueue, ^{
[self countFrom400To500];
});
}
- (void)countTo100
{
for (int i = 0; i < 100; i++) {
NSLog(@"%d", i);
}
}
- (void)countFrom200To400
{
for (int i = 200; i < 400; i++) {
NSLog(@"%d", i);
}
}
- (void)countFrom400To500
{
for (int i = 400; i < 500; i++) {
NSLog(@"%d", i);
}
}
如果从上面查看日志,它将首先从0 .. 100打印,然后从200 .. 400和400 .. 500打印。
现在,请考虑以下代码段,您可以在其中执行并发块中的每个方法,例如
-(void)testSerialQueue
{
dispatch_queue_t serialQueue = dispatch_queue_create("com.serial.queue", DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQueue, ^{
[self countTo100];
});
dispatch_async(serialQueue, ^{
[self countFrom200To400];
});
dispatch_async(serialQueue, ^{
[self countFrom400To500];
});
}
- (void)countTo100
{
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"%d", i);
}
});
}
- (void)countFrom200To400
{
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{
for (int i = 200; i < 400; i++) {
NSLog(@"%d", i);
}
});
}
- (void)countFrom400To500
{
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{
for (int i = 400; i < 500; i++) {
NSLog(@"%d", i);
}
});
}
这里,您在串行队列中添加了所有方法,但方法本身在并发块中运行。因此,在这种情况下,结果是随机的。你也可以使用像这样的dispatch_group序列化它,
-(void)testSerialQueue
{
dispatch_queue_t serialQueue = dispatch_queue_create("com.serial.queue", DISPATCH_QUEUE_SERIAL);
self.group = dispatch_group_create();
dispatch_async(serialQueue, ^{
[self countTo100];
});
dispatch_async(serialQueue, ^{
[self countFrom200To400];
});
dispatch_async(serialQueue, ^{
[self countFrom400To500];
});
}
- (void)countTo100
{
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_enter(self.group);
dispatch_async(concurrentQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"%d", i);
}
dispatch_group_leave(self.group);
});
dispatch_group_wait(self.group, DISPATCH_TIME_FOREVER);
}
- (void)countFrom200To400
{
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_enter(self.group);
dispatch_async(concurrentQueue, ^{
for (int i = 200; i < 400; i++) {
NSLog(@"%d", i);
}
dispatch_group_leave(self.group);
});
dispatch_group_wait(self.group, DISPATCH_TIME_FOREVER);
}
- (void)countFrom400To500
{
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_enter(self.group);
dispatch_async(concurrentQueue, ^{
for (int i = 400; i < 500; i++) {
NSLog(@"%d", i);
}
dispatch_group_leave(self.group);
});
dispatch_group_wait(self.group, DISPATCH_TIME_FOREVER);
}
在这里,您将再次看到它按顺序打印日志。因此,dispatch_group用于序列化并发操作。您可能希望此时在serialQueue中删除dispatch_async。
现在,操作队列,让我们看一下简单的例子,
-(void)testSerialQueue
{
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 1;
NSBlockOperation *operation1 = [[NSBlockOperation alloc] init];
NSBlockOperation *operation2 = [[NSBlockOperation alloc] init];
NSBlockOperation *operation3 = [[NSBlockOperation alloc] init];
[operation1 addExecutionBlock:^{
[self countTo100];
}];
[operation2 addExecutionBlock:^{
[self countFrom200To400];
}];
[operation3 addExecutionBlock:^{
[self countFrom400To500];
}];
}
- (void)countTo100
{
for (int i = 0; i < 100; i++) {
NSLog(@"%d", i);
}
}
- (void)countFrom200To400
{
for (int i = 200; i < 400; i++) {
NSLog(@"%d", i);
}
}
- (void)countFrom400To500
{
for (int i = 400; i < 500; i++) {
NSLog(@"%d", i);
}
}
计数方法被添加到NSOperationQueue中,maxConcurrentOperation为&#39; 1&#39;现在更像是一个串行队列。每个方法都不会产生一些其他队列,因此,计数在同一个串行队列上执行。所以,它们都是有序打印的。
现在,让我们看一个模拟你案例的例子。
-(void)testSerialQueue
{
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 1;
NSBlockOperation *operation1 = [[NSBlockOperation alloc] init];
NSBlockOperation *operation2 = [[NSBlockOperation alloc] init];
NSBlockOperation *operation3 = [[NSBlockOperation alloc] init];
[operation1 addExecutionBlock:^{
[self countTo100];
}];
[operation2 addExecutionBlock:^{
[self countFrom200To400];
}];
[operation3 addExecutionBlock:^{
[self countFrom400To500];
}];
}
- (void)countTo100
{
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"%d", i);
}
});
}
- (void)countFrom200To400
{
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{
for (int i = 200; i < 400; i++) {
NSLog(@"%d", i);
}
});
}
- (void)countFrom400To500
{
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{
for (int i = 400; i < 500; i++) {
NSLog(@"%d", i);
}
});
}
在此用例中,您将操作添加到NSOperationQueue(即一个串行队列),但同样,各个方法在其他一些并发队列中运行。因此,执行顺序非常随机。现在,您可以像使用串行队列一样使用dispatch_group来解决这个问题。
-(void)testSerialQueue
{
self.group = dispatch_group_create();
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 1;
NSBlockOperation *operation1 = [[NSBlockOperation alloc] init];
NSBlockOperation *operation2 = [[NSBlockOperation alloc] init];
NSBlockOperation *operation3 = [[NSBlockOperation alloc] init];
[operation1 addExecutionBlock:^{
[self countTo100];
}];
[operation2 addExecutionBlock:^{
[self countFrom200To400];
}];
[operation3 addExecutionBlock:^{
[self countFrom400To500];
}];
}
- (void)countTo100
{
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_enter(self.group);
dispatch_async(concurrentQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"%d", i);
}
dispatch_group_leave(self.group);
});
dispatch_group_wait(self.group, DISPATCH_TIME_FOREVER);
}
- (void)countFrom200To400
{
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_enter(self.group);
dispatch_async(concurrentQueue, ^{
for (int i = 200; i < 400; i++) {
NSLog(@"%d", i);
}
dispatch_group_leave(self.group);
});
dispatch_group_wait(self.group, DISPATCH_TIME_FOREVER);
}
- (void)countFrom400To500
{
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_enter(self.group);
dispatch_async(concurrentQueue, ^{
for (int i = 400; i < 500; i++) {
NSLog(@"%d", i);
}
dispatch_group_leave(self.group);
});
dispatch_group_wait(self.group, DISPATCH_TIME_FOREVER);
}
现在,您将看到计数再次有序。这是因为dispatch_group等待每个异步任务完成。
对于您的特定用例,您可以使用循环来调用某些方法,像这样创建NSInvocationOperation,
-(void)testSerialQueue
{
self.group = dispatch_group_create();
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 1;
NSArray *selectors = @[@"countTo100", @"countFrom200To400", @"countFrom400To500"];
for (NSString *selector in selectors) {
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
selector:NSSelectorFromString(selector)
object:nil];
[queue addOperation:operation];
}
}
- (void)countTo100
{
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_enter(self.group);
dispatch_async(concurrentQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"%d", i);
}
dispatch_group_leave(self.group);
});
dispatch_group_wait(self.group, DISPATCH_TIME_FOREVER);
}
- (void)countFrom200To400
{
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_enter(self.group);
dispatch_async(concurrentQueue, ^{
for (int i = 200; i < 400; i++) {
NSLog(@"%d", i);
}
dispatch_group_leave(self.group);
});
dispatch_group_wait(self.group, DISPATCH_TIME_FOREVER);
}
- (void)countFrom400To500
{
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_enter(self.group);
dispatch_async(concurrentQueue, ^{
for (int i = 400; i < 500; i++) {
NSLog(@"%d", i);
}
dispatch_group_leave(self.group);
});
dispatch_group_wait(self.group, DISPATCH_TIME_FOREVER);
}
答案 1 :(得分:1)
您的目标方法是异步的。这意味着您不能使用普通块操作,您需要创建一个自定义操作子类,以便在异步方法完成之前操作不会完成。
在google中搜索为示例创建异步操作子类的示例,因为您需要组织一些事项。
或者你可以拥有类似文件数组(或其他类似内容),每次异步方法完成后检查是否有任何文件,删除第一个项目并进行处理。这将持续到阵列为空......
答案 2 :(得分:0)
您可以使用信号量等待功能完成,如果成功再次使用参数调用它。