如何使用三个请求同时正确创建并发队列

时间:2015-04-23 11:04:15

标签: ios objective-c uitableview grand-central-dispatch

我希望同时获得三个请求以提高性能。 这是我当前的代码,它在我的tableview上只返回一个平台:

 dispatch_queue_t concurrentQueue = dispatch_queue_create("com.myapp.myqueue", DISPATCH_QUEUE_CONCURRENT);

void(^block_readPS4)() = ^{
    self.releasesDict = [NSDictionary dictionaryWithDictionary:[self getDataWithPlatform:@"ps4"]];
};
void(^block_readXONE)() = ^{
    self.releasesDict = [NSDictionary dictionaryWithDictionary:[self getDataWithPlatform:@"xboxone"]];
};
void(^block_readPC)() = ^{
    self.releasesDict = [NSDictionary dictionaryWithDictionary:[self getDataWithPlatform:@"pc"]];
};
void(^block_write)() = ^{dictionaryWithDictionary:self.releasesDict];
    self.releasesArr = [self.releasesDict allKeys];
    [self.tableView reloadData];
    [self.activityInd stopAnimating];
};
dispatch_async(concurrentQueue,block_readPS4);
dispatch_async(concurrentQueue,block_readXONE);
dispatch_async(concurrentQueue,block_readPC);

dispatch_barrier_async(concurrentQueue, block_write);

我知道问题是写在self.releasesDict,它是如何改进的?

2 个答案:

答案 0 :(得分:4)

@ryancrunchi是正确的:

  

你在每次阅读中都会覆盖self.releasesDict。所以在你的写作中   阻止self.releasesDict的值将是最后一次读取的   系统执行。

...但是他提出的解决方案并不能保护字典免于并发写入,NSMutableDictionary本质上不是线程安全的。您必须保护它免受并发读取和写入和/或写入+写入。这是您可能采用的一种方式(详细介绍了评论中所做的一切):

// A local (non-shared) mutable dictionary. Using a local dictionary allows us to know that no one
// else is reading from or writing to it concurrently, which is not guaranteed if we use self.releasesDict
NSMutableDictionary* localDict = [NSMutableDictionary dictionary];

// Your original concurrent queue
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.myapp.myqueue", DISPATCH_QUEUE_CONCURRENT);

// A serial queue to protect localDict from reading and writing.
dispatch_queue_t localDictWriteQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);

// Make this queue target the concurrent queue. Not strictly required, but you had everything executing on
// concurrentQueue before, and this preserves that, while also protecting localDict.
dispatch_set_target_queue(localDictWriteQueue, concurrentQueue);

// A dispatch group that allows us to perform an operation only after all the constituent writes have finished.
dispatch_group_t group = dispatch_group_create();

// For each platform, enter the group, then fire off the concurrent block
dispatch_group_enter(group);
dispatch_async(concurrentQueue, ^{
    // Fetch into a dictionary that is local to the block.
    NSDictionary* x = [self getDataWithPlatform:@"ps4"];

    // Then, on the serial localDictWriteQueue merge those entries into the shared local dictionary
    dispatch_async(localDictWriteQueue, ^{
        [localDict addEntriesFromDictionary: x];
        // This balances out the dispatch_group_enter operation we did right before we enqueued this
        dispatch_group_leave(group);
    });
});

// Second verse, same as the first
dispatch_group_enter(group);
dispatch_async(concurrentQueue, ^{
    NSDictionary* x = [self getDataWithPlatform:@"xboxone"];
    dispatch_async(localDictWriteQueue, ^{
        [localDict addEntriesFromDictionary: x];
        dispatch_group_leave(group);
    });
});

// Third verse, same as the first
dispatch_group_enter(group);
dispatch_async(concurrentQueue, ^{
    NSDictionary* x = [self getDataWithPlatform:@"pc"];
    dispatch_async(localDictWriteQueue, ^{
        [localDict addEntriesFromDictionary: x];
        dispatch_group_leave(group);
    });
});

// Then set up the block we want to run at the end... use main queue because it updates UI.
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    // Update self.releasesDict all at once, on the main thread
    // Note: we do not need to do this read of localDict on localDictWriteQueue because if this block is executing, we know (semantically) that all possible
    // write operations have already completed, and that no other writes to localDict are possible because it's local to this method call.
    self.releasesDict = localDict;
    // Same idea
    self.releasesArr = [self.releasesDict allKeys];

    // Update UI based on state changes to self.
    [self.tableView reloadData];
    [self.activityInd stopAnimating];
});

答案 1 :(得分:1)

您在每次阅读中都会覆盖self.releasesDict。因此,在您的写入块中,self.releasesDict的值将是系统执行的最后一次读取。如果您希望在同一个NSDictionary中读取所有内容,请将self.releasesDict声明为NSMutableDictionary并使用以下命令初始化:

self.releasesDict = [NSMutableDictionary dictionary];

并在你的阅读中:

[self.releasesDict addEntriesFromDictionary:[NSDictionary dictionaryWithDictionary:/*what you want*/]];