运行多个后台线程iOS [英] Running multiple background threads iOS

查看:60
本文介绍了运行多个后台线程iOS的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否可以运行多个后台线程来提高iOS上的性能.目前,我正在使用以下代码在后台线程上发送50个网络请求,例如:

Is it possible to run multiple background threads to improve performance on iOS . Currently I am using the following code for sending lets say 50 network requests on background thread like this:

 dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
            // send 50 network requests 
 });

将我的代码更新为类似内容后,没有获得性能提升:(取自这里

After updating my code to something like this no performance gain was achieved :( Taken from here

dispatch_queue_t fetchQ = dispatch_queue_create("Multiple Async Downloader", NULL);
dispatch_group_t fetchGroup = dispatch_group_create();

// This will allow up to 8 parallel downloads.
dispatch_semaphore_t downloadSema = dispatch_semaphore_create(8);

// We start ALL our downloads in parallel throttled by the above semaphore.
for (NSURL *url in urlsArray) {
    dispatch_group_async(fetchGroup, fetchQ, ^(void) {
        dispatch_semaphore_wait(downloadSema, DISPATCH_TIME_FOREVER);
        NSMutableURLRequest *headRequest = [NSMutableURLRequest requestWithURL:url  cachePolicy: NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
        [headRequest setHTTPMethod: @"GET"];
        [headRequest addValue: cookieString forHTTPHeaderField: @"Cookie"];

         NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease];
        [NSURLConnection sendAsynchronousRequest:headRequest
                                           queue:queue // created at class init
                               completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
                                   // do something with data or handle error
                                   NSLog(@"request completed");
                               }];
        dispatch_semaphore_signal(downloadSema);
    });
}

// Now we wait until ALL our dispatch_group_async are finished.
dispatch_group_wait(fetchGroup, DISPATCH_TIME_FOREVER);

// Update your UI
dispatch_sync(dispatch_get_main_queue(), ^{
    //[self updateUIFunction];
});

// Release resources
dispatch_release(fetchGroup);
dispatch_release(downloadSema);
dispatch_release(fetchQ);

推荐答案

注意不要将线程与队列混淆

单个并发队列可以跨多个线程运行,并且GCD不能保证您的任务将在哪个线程上运行.

Be careful not to confuse threads with queues

A single concurrent queue can operate across multiple threads, and GCD never guarantees which thread your tasks will run on.

您当前拥有的代码将提交50个网络任务,以在后台并发队列上运行,这很正确.

The code you currently have will submit 50 network tasks to be run on a background concurrent queue, this much is true.

但是,所有这50个任务都将在相同线程上执行.

However, all 50 of these tasks will be executed on the same thread.

GCD基本上就像一个巨型线程池,因此您的块(包含50个任务)将被提交到池中的下一个可用线程.因此,如果任务是同步的,则将串行执行.这意味着每个任务都必须等待上一个任务完成才可以执行.如果它们是异步任务,则它们将全部立即分派(这就是为什么首先需要使用GCD的问题.

GCD basically acts like a giant thread pool, so your block (containing your 50 tasks) will be submitted to the next available thread in the pool. Therefore, if the tasks are synchronous, they will be executed serially. This means that each task will have to wait for the previous one to finish before preceding. If they are asynchronous tasks, then they will all be dispatched immediately (which begs the question of why you need to use GCD in the first place).

如果要同时运行多个同步任务,则每个任务都需要一个单独的dispatch_async.这样,您就有了一个 per 任务,因此它们将从线程池中分派到多个线程,因此可以并行运行.

If you want multiple synchronous tasks to run at the same time, then you need a separate dispatch_async for each of your tasks. This way you have a block per task, and therefore they will be dispatched to multiple threads from the thread pool and therefore can run concurrently.

尽管您应注意不要提交过多的网络任务以同时操作(您未明确说明它们在做什么),因为这可能会导致服务器,如gnasher所说 .

Although you should be careful that you don't submit too many network tasks to operate at the same time (you don't say specifically what they're doing) as it could potentially overload a server, as gnasher says.

您可以使用GCD 信号量轻松限制同时运行的并发任务(无论是同步任务还是异步任务)的数量.例如,此代码将并发操作数限制为6:

You can easily limit the number of concurrent tasks (whether they're synchronous or asynchronous) operating at the same time using a GCD semaphore. For example, this code will limit the number of concurrent operations to 6:

long numberOfConcurrentTasks = 6;

dispatch_semaphore_t semaphore = dispatch_semaphore_create(numberOfConcurrentTasks);

for (int i = 0; i < 50; i++) {

    dispatch_async(concurrentQueue, ^{

        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

        [self doNetworkTaskWithCompletion:^{
            dispatch_semaphore_signal(semaphore);
            NSLog(@"network task %i done", i);
        }];

    });

}


编辑

您的代码存在问题:


Edit

The problem with your code is the line:

dispatch_queue_t fetchQ = dispatch_queue_create("Multiple Async Downloader", NULL);

NULL传递给attr参数时,GCD会创建一个串行队列(如果您实际上在此处指定队列类型,它也更具可读性).您需要并发队列.因此,您需要:

When NULL is passed to the attr parameter, GCD creates a serial queue (it's also a lot more readable if you actually specify the queue type here). You want a concurrent queue. Therefore you want:

dispatch_queue_t fetchQ = dispatch_queue_create("Multiple Async Downloader", DISPATCH_QUEUE_CONCURRENT);

您需要从请求的结束处理程序内发出信号量,而不是在请求结束时发出信号量.由于它是异步的,因此一旦发出请求,便会发出信号,从而使另一个网络任务排队.您要等待网络任务返回后再发出信号.

You need to be signalling your semaphore from within the completion handler of the request instead of at the end of the request. As it's asynchronous, the semaphore will get signalled as soon as the request is sent off, therefore queueing another network task. You want to wait for the network task to return before signalling.

[NSURLConnection sendAsynchronousRequest:headRequest
                                       queue:queue // created at class init
                           completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
                           // do something with data or handle error
                           NSLog(@"request completed");
                           dispatch_semaphore_signal(downloadSema);
                       }];


编辑2

我刚刚注意到您正在使用dispatch_sync更新UI.我认为它没有同步的理由,因为它只会阻塞后台线程,直到主线程更新了UI.我会用dispatch_async来做到这一点.


Edit 2

I just noticed you are updating your UI using a dispatch_sync. I see no reason for it to be synchronous, as it'll just block the background thread until the main thread has updated the UI. I would use a dispatch_async to do this.

CouchDeveloper指出,并发数量有可能网络请求可能已被系统限制.

As CouchDeveloper points out, it is possible that the number of concurrent network requests might be being capped by the system.

最简单的解决方案似乎正在迁移到 NSURLSession 并配置所用NSOperationQueuemaxConcurrentOperationCount属性.这样,您可以完全放弃信号量,并使用回调在主线程上更新UI,从而将所有网络请求分配到后台队列中.

The easiest solution appears to be migrating over to NSURLSession and configuring the maxConcurrentOperationCount property of the NSOperationQueue used. That way you can ditch the semaphores altogether and just dispatch all your network requests on a background queue, using a callback to update the UI on the main thread.

不过,我对NSURLSession一点都不熟悉,我只是从GCD的角度来回答这个问题.

I am not at all familiar with NSURLSession though, I was only answering this from a GCD stand-point.

这篇关于运行多个后台线程iOS的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆