1

谁能回答我,下面的代码怎么会吃掉一个 C2D 2.6GHz CPU 的整个内核?它只下载 10MB 块的文件,可能有 600 个,但 NSOperationQueue 有 6 个并发任务的限制。

为什么在 Windows 上同样的应用程序(用 C# 编写的只吃 2%,而不是 80%!),它只是一个简单的 HTTP 请求!

for (DownloadFile *downloadFile in [download filesInTheDownload])
            {
                for (DownloadChunk *downloadChunk in [downloadFile chunksInTheFile])
                {
                    NSString *downloadPath = [[NSString stringWithFormat:@"%@/%@", [download downloadFolder], [download escapedTitle]] stringByExpandingTildeInPath];
                    NSString *chunkPath = [downloadPath stringByAppendingFormat:@"/%@.%i", [downloadFile fileName], [downloadChunk chunkId]];

                    NSError *attributesError = nil;

                    NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:chunkPath error:&attributesError];

                    NSNumber *fileSizeNumber = [fileAttributes objectForKey:NSFileSize];
                    uint64_t fileSize = [fileSizeNumber longLongValue];
                    NSLog(@"Chunk file size: %lli", fileSize);
                    uint64_t expectedSize = ([downloadChunk endingByte] - [downloadChunk startingByte]) + 1;
                    NSLog(@"Chunk expected size: %lli", expectedSize);
                    uint64_t newStartingByte = [downloadChunk startingByte] + fileSize;
                    if (fileSize == expectedSize)
                    {
                        NSLog(@"Chunk complete: %@.%i", [downloadFile fileName], [downloadChunk chunkId]);
                    }
                    else
                    {
                        NSURL *fileURL = [[NSURL alloc] initWithString:[downloadFile filePath]];

                        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:fileURL];
                        NSLog(@"Normal range: %lli-%lli", [downloadChunk startingByte], [downloadChunk endingByte]);
                        NSString *range = [NSString stringWithFormat:@"bytes=%lli-%lli", newStartingByte, [downloadChunk endingByte]];
                        [request setValue:range forHTTPHeaderField:@"Range"];
                        AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
                        operation.outputStream = [NSOutputStream outputStreamToFileAtPath:chunkPath append:YES];

                        [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
                            NSLog(@"%@", [NSString stringWithFormat:@"Chunk complete: %@.%i", [downloadFile fileName], [downloadChunk chunkId]]);
                            if (download.downloadedBytes == download.size)
                                [[NSNotificationCenter defaultCenter] postNotificationName:@"downloadFinished" object:download];
                        } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                            NSLog(@"Error: %@", error);
                        }];

                        [operation setDownloadProgressBlock:^(NSInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
                            download.downloadedBytes += bytesRead;
                        }];

                        [queue addOperation:operation];
                    }
                }
            }

这是一些时间分析器屏幕截图,如果我没看错的话,似乎一切都是因为 RunLoops。

在此处输入图像描述 在此处输入图像描述

4

2 回答 2

0

似乎将大多数属性降级为非原子似乎会将使用率从 80% 降低到 20-30%。现在只有下载的字节是原子的。我还能做些什么来改进?

于 2012-08-03T15:03:12.667 回答
0

假设最后一个进度块完成下载,你有点像把一个圆钉塞进一个方孔。我不确定这是否会导致您的 CPU 使用率过高,但我肯定会解决这个问题。AFNetworking 有一个专门用于此的功能[AFHTTPRequestOperation setCompletionBlockWithSuccess:failure:],记录在这里。将根据返回的 HTTP 状态代码调用正确的块。

换句话说,而不是这样:

    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
    operation.outputStream = [NSOutputStream outputStreamToFileAtPath:chunkPath append:YES];
    [operation setDownloadProgressBlock:^(NSInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
        download.downloadedBytes += bytesRead;
        if (download.downloadedBytes == download.size)
            [[NSNotificationCenter defaultCenter] postNotificationName:@"downloadFinished" object:download];
    }];

    [queue addOperation:operation];
    chunkId++;

用这个:

    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
    operation.outputStream = [NSOutputStream outputStreamToFileAtPath:chunkPath append:YES];
    [output setCompletionBlockWithSuccess: ^(AFHTTPRequestOperation *operation, id responseObject) {
    [[NSNotificationCenter defaultCenter] postNotificationName:@"downloadFinished" object:download];
                                        }
                                  failure: ^(AFHTTPRequestOperation *operation, NSError *error) {
    // you should probably do something here
                                        }];

在那之后,我怀疑你甚至需要下载字节。这将删除您的最后一个原子属性,这应该会有所改善。

于 2012-08-10T16:40:13.777 回答