Grand Central Dispatch 与 NSThread
我为 NSThread 和 Grand Central Dispatch (GCD) 创建了一些测试代码:
- (void)doIt:(NSNumber *)i
{
sleep(1);
NSLog(@"Thread#%i", [i intValue]);
}
- (IBAction)doWork:(id)sender
{
for (int i = 0; 10 > i; i++) {
NSNumber *t = [NSNumber numberWithInt:i];
[NSThread detachNewThreadSelector:@selector(doIt:) toTarget:self withObject:t];
}
sleep(1);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(10, queue, ^(size_t i) {
sleep(1);
NSLog(@"GCD#%u",(int)i);
});
}
结果:
2011-04-13 19:41:07.806 GDC[1494:5e03] Thread#0
2011-04-13 19:41:07.813 GDC[1494:6903] Thread#3
2011-04-13 19:41:07.812 GDC[1494:6403] Thread#2
2011-04-13 19:41:07.812 GDC[1494:5f03] Thread#1
2011-04-13 19:41:07.813 GDC[1494:6e03] Thread#4
2011-04-13 19:41:07.814 GDC[1494:7303] Thread#5
2011-04-13 19:41:07.814 GDC[1494:7803] Thread#6
2011-04-13 19:41:07.815 GDC[1494:7d03] Thread#7
2011-04-13 19:41:07.815 GDC[1494:8203] Thread#8
2011-04-13 19:41:07.816 GDC[1494:8703] Thread#9
2011-04-13 19:41:08.812 GDC[1494:707] GCD#0
2011-04-13 19:41:09.816 GDC[1494:707] GCD#1
2011-04-13 19:41:10.819 GDC[1494:707] GCD#2
2011-04-13 19:41:11.825 GDC[1494:707] GCD#3
2011-04-13 19:41:12.828 GDC[1494:707] GCD#4
2011-04-13 19:41:13.833 GDC[1494:707] GCD#5
2011-04-13 19:41:14.838 GDC[1494:707] GCD#6
2011-04-13 19:41:15.848 GDC[1494:707] GCD#7
2011-04-13 19:41:16.853 GDC[1494:707] GCD#8
2011-04-13 19:41:17.857 GDC[1494:707] GCD#9
NSThreads 按我的预期工作:任务同时运行,每个线程休眠 1 秒。
dispatch_apply 没有按我的预期工作:为什么顺序是连续的?为什么每个循环都要等到前一个循环完成?
感谢您的帮助。
I created some test code for NSThread and Grand Central Dispatch (GCD):
- (void)doIt:(NSNumber *)i
{
sleep(1);
NSLog(@"Thread#%i", [i intValue]);
}
- (IBAction)doWork:(id)sender
{
for (int i = 0; 10 > i; i++) {
NSNumber *t = [NSNumber numberWithInt:i];
[NSThread detachNewThreadSelector:@selector(doIt:) toTarget:self withObject:t];
}
sleep(1);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(10, queue, ^(size_t i) {
sleep(1);
NSLog(@"GCD#%u",(int)i);
});
}
And the results:
2011-04-13 19:41:07.806 GDC[1494:5e03] Thread#0
2011-04-13 19:41:07.813 GDC[1494:6903] Thread#3
2011-04-13 19:41:07.812 GDC[1494:6403] Thread#2
2011-04-13 19:41:07.812 GDC[1494:5f03] Thread#1
2011-04-13 19:41:07.813 GDC[1494:6e03] Thread#4
2011-04-13 19:41:07.814 GDC[1494:7303] Thread#5
2011-04-13 19:41:07.814 GDC[1494:7803] Thread#6
2011-04-13 19:41:07.815 GDC[1494:7d03] Thread#7
2011-04-13 19:41:07.815 GDC[1494:8203] Thread#8
2011-04-13 19:41:07.816 GDC[1494:8703] Thread#9
2011-04-13 19:41:08.812 GDC[1494:707] GCD#0
2011-04-13 19:41:09.816 GDC[1494:707] GCD#1
2011-04-13 19:41:10.819 GDC[1494:707] GCD#2
2011-04-13 19:41:11.825 GDC[1494:707] GCD#3
2011-04-13 19:41:12.828 GDC[1494:707] GCD#4
2011-04-13 19:41:13.833 GDC[1494:707] GCD#5
2011-04-13 19:41:14.838 GDC[1494:707] GCD#6
2011-04-13 19:41:15.848 GDC[1494:707] GCD#7
2011-04-13 19:41:16.853 GDC[1494:707] GCD#8
2011-04-13 19:41:17.857 GDC[1494:707] GCD#9
NSThreads work as I expected: The tasks run concurrently and each thread sleeps for 1 second.
The dispatch_apply does not work as I expected: Why is the order sequential? Why does each loop wait until the previous loop finishes?
Thanks for the help.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
由于您的设备只有一个处理器,因此 GCD 可能只会创建一个线程来执行块,并且您的块会按顺序执行。不过,您已经创建了 10 个不同的线程,并且每个线程都获得了一小部分可用处理时间。幸运的是,睡眠并不是非常消耗处理器资源,因此所有线程都可以很好地一起运行。在具有 4 或 8 个处理核心的机器上尝试类似的测试,您将看到 GCD 并行运行更多块。
GCD 的好处并不在于它一定提供比线程更好的性能,而是程序员不必考虑创建线程或将线程数量与可用处理器数量相匹配。您可以创建许多小任务,这些任务将在处理器可用时执行,并让系统为您安排这些任务。
编辑:我在 Mac 上的一个简单的命令行程序中对您的代码进行了一些操作。正如我在下面的评论中所建议的,以及 @Ren-D 的回答中提到的,使用
dispatch_async()
而不是dispatch_apply()
会产生很大的差异。这是我使用的代码:如您所见,我用花费一些时间进行计数的
for
循环替换了sleep()
调用。 (我在 MacBook Pro 上运行了代码 - 如果您在 iPhone 上运行,则可能需要向下调整MAX_COUNT
的值。)如果您使用sleep()
在线程和块中,然后dispatch_async()
使块的行为就像线程一样 - 所有块同时运行并大约在同一时间完成。切换到计数会改变这种行为——多个线程同时运行,但块按组执行(我的机器有两个处理器核心,因此它以两个为一组运行块)。这正是您所期望的; GCD 的工作是将任务排队并尽快完成它们,充分利用可用资源,而不是同时运行尽可能多的任务。以下是上面代码的输出:
请注意,其中两个块实际上在除一个线程之外的所有线程之前完成。另外:代码末尾的
sleep(15)
只是让线程和块在程序终止之前记录它们的消息。根据您将代码粘贴到的程序类型,您可能不需要它。Because your device only has one processor, GCD probably only creates one thread for executing blocks and your blocks execute sequentially. You've created 10 different threads, though, and those each get a little piece of the available processing time. Fortunately, sleeping isn't very processor-intensive, so all your threads run together pretty well. Try a similar test on a machine with 4 or 8 processing cores, and you'll see GCD run more of your blocks in parallel.
The nice thing about GCD isn't that it necessarily offers better performance than threads, it's that the programmer doesn't have to think about creating threads or matching the number of threads to the number of available processors. You can create lots of little tasks that will execute as a processor becomes available and let the system schedule those tasks for you.
Edit: I played around with your code a bit in a simple command-line program on my Mac. As I suggested in my comment below, and also mentioned in @Ren-D's answer, using
dispatch_async()
rather thandispatch_apply()
makes a big difference. Here's the code I used:As you can see, I replaced your
sleep()
calls withfor
loops that spend some time counting. (I ran the code on a MacBook Pro -- you might want to adjust the value ofMAX_COUNT
downward if you're running on an iPhone.) If you usesleep()
in both the threads and the block, thendispatch_async()
makes the blocks behave just like the threads -- all blocks run concurrently and complete at about the same time. Switching to counting changes that behavior -- multiple threads all run concurrently, but the blocks execute in groups (my machine has two processor cores, so it ran the blocks in groups of two). This is exactly as you'd expect; GCD's job is to queue tasks and finish them as quickly as possible making the best use of available resources, not to run as many tasks concurrently as possible.Here's output from the code above:
Note that two of the blocks actually finished before all but one of the threads. Also: the
sleep(15)
at the end of the code is just there to let the threads and blocks log their messages before the program terminates. Depending on what sort of program you paste the code into, you may not need it.尝试查看此网站: http:// /developer.apple.com/library/ios/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html
在IOS环境下,据说
dispatch_apply
会依赖于队列传入,如果目标队列是由dispatch_get_global_queue
返回的并发队列(这是您的情况),则可以并发调用该块。所以,我认为它正在工作,只是碰巧它像异步运行一样运行。此外,代码运行的设备可能会对结果产生影响(如 @Caleb 提到的)。但我的建议是,也许尝试一下dispatch_async?
Try to look at this website: http://developer.apple.com/library/ios/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html
In IOS environment, It is said that
dispatch_apply
will depend on the queue passed in, if the target queue is a concurrent queue returned bydispatch_get_global_queue
(which is your case), the block can be invoked concurrently.So, I think it IS working, just so it happens that it is run as if it runs asynchronously. Also, which device the code is run at could play a role on the result (like mentioned by @Caleb). But my suggestion is, maybe try
dispatch_async
instead?如果有人想测试哪种方法最适合解决 spedify 问题,这里是代码:
If anyone want to test, which method is the best for the spedify probleme, here ist the code: