作者:Love@YR
链接:http://blog.youkuaiyun.com/jingqiu880905/article/details/51839499
请尊重原创,谢谢!
建议先弄清同步异步 串行并行区别:参考这篇文章
dispatch_queue_t 串行并行队列 相当于NSOperationQueue
dispatch_async/sync 里block构成的异步/同步任务 相当于NSOperation
ios7.0之后NSOperation的isConcurrent被deprecated,改成了isAsynchronous,改完后跟上面对应。
官方文档 Table 2-2前面那段话描述说:
Operation objects execute in a synchronous manner by default—that is, they perform their task in the thread that calls their start method. Because operation queues provide threads for nonconcurrent operations, though, most operations still run asynchronously. However, if you plan to execute operations manually and still want them to run asynchronously, you must take the appropriate actions to ensure that they do. You do this by defining your operation object as a concurrent operation.
即NSOperation对象默认情况下是同步执行的。同步意味着阻塞。意思即此Operation是在调用它start方法的那个线程里执行其任务的。(所以说你在主线程创建一个operation,然后并不重写这个operation的start方法,直接调用其start方法的话就会使得此任务直接在主线程里执行。)
但是由于operation queues 是会自动为加在其里面的非并发operation创建线程的(这部分代码我们看不到,应该是addOperation方法里取出此operation然后new了一个子线程再执行这个operation的start方法),所以即使你的operation设置的isConcurrent为NO(或者未重写isConcurrent方法),把operation加入operation queue此operation也会异步执行。
所以说如果你不想把operation加入operation queue里,即你要手动去调用其start方法,然后你还想让它异步执行的话,你就需要自己在代码里实现了。
后来我碰到一个问题,因为AFNetWorking的请求操作是异步的,AFURLConnectionOperation的isConcurrent是YES,但是我想同步执行一个请求,就是想拿到请求结果再走下面的代码怎么办呢?它的start方法又自己创建了子线程。我怎样能在主线程里同步执行这个请求呢?
两句:1. 调用start 2.调用 waitUntilFinished。
因为waitUntilFinished保证了阻塞当前线程而等待操作完成即把这个操作改成了同步的。
可以参考:http://www.kwstu.com/ArticleView/guandebao_20139616530941
还有就是一般为operation创建线程的事情都是由operation queue去做,那么AFURLConnectionOperation 为什么要在start方法里自己创建子线程呢?看到了这篇文章:
http://blog.sina.com.cn/s/blog_74e9d98d0101h1hk.html
还有一个问题就是一个operation是代表一个线程吗?
答案:不是。
那么一个operation是代表一个任务吗?
答案:也不是。
参考:http://www.cnblogs.com/wendingding/p/3809042.html
这篇文章的NSBlockOperation例子可以说明operation只是一系列动作的集合。这一系列动作可以并发执行。可以在不同的线程里。
为了更直观地说明任务 线程 操作之间的关系,我们看下面的代码:
- (IBAction)buttonTaped:(id)sender {
dispatch_queue_t myQueue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(myQueue, ^{
for (NSInteger i = 0; i < 500000000; i++) {
if (i == 0) {
NSLog(@"a1s1 for循环->开始%@",[NSThread currentThread]);
}
if (i == 499999999) {
NSLog(@"a1s1 for循环->完成");
}
}
dispatch_async(myQueue, ^{
for (NSInteger i = 0; i < 500000000; i++) {
if (i == 0) {
NSLog(@"a1a1 -> 开始%@",[NSThread currentThread]);
}
if (i == 499999999) {
NSLog(@"a1a1 -> 完成");
}
}});
for (NSInteger n = 0; n < 2; n++) {
dispatch_sync(myQueue, ^{
for (NSInteger i = 0; i < 500000000; i++) {
if (i == 0) {
NSLog(@"a1s%ld-> 开始%@",(long)n+1,[NSThread currentThread]);
}
if (i == 499999999) {
NSLog(@"a1s%ld -> 完成",(long)n+1);
}
}
});
}
dispatch_async(myQueue, ^{
for (NSInteger i = 0; i < 500000000; i++) {
if (i == 0) {
NSLog(@"a1a2 -> 开始%@",[NSThread currentThread]);
}
if (i == 499999999) {
NSLog(@"a1a2 -> 完成");
}
}});
});
dispatch_async(myQueue, ^{
for (NSInteger i = 0; i < 500000000; i++) {
if (i == 0) {
NSLog(@"a2-> 开始%@",[NSThread currentThread]);
}
if (i == 499999999) {
NSLog(@"a2-> 完成");
}
}});
NSLog(@"阻塞我没有?当前线程%@",[NSThread currentThread]);
}
运行结果:
2016-07-06 17:29:58.316 threadDemo[1241:185626] a2-> 开始<NSThread: 0x7fdbcad065e0>{number = 3, name = (null)}
2016-07-06 17:29:58.316 threadDemo[1241:185464] 阻塞我没有?当前线程<NSThread: 0x7fdbcac01280>{number = 1, name = main}
2016-07-06 17:29:58.316 threadDemo[1241:185642] a1s1 for循环->开始<NSThread: 0x7fdbcae1a6a0>{number = 2, name = (null)}
2016-07-06 17:29:59.594 threadDemo[1241:185642] a1s1 for循环->完成
2016-07-06 17:29:59.594 threadDemo[1241:185626] a2-> 完成
2016-07-06 17:29:59.594 threadDemo[1241:185642] a1s1-> 开始<NSThread: 0x7fdbcae1a6a0>{number = 2, name = (null)}
2016-07-06 17:29:59.594 threadDemo[1241:185626] a1a1 -> 开始<NSThread: 0x7fdbcad065e0>{number = 3, name = (null)}
2016-07-06 17:30:00.849 threadDemo[1241:185642] a1s1 -> 完成
2016-07-06 17:30:00.850 threadDemo[1241:185642] a1s2-> 开始<NSThread: 0x7fdbcae1a6a0>{number = 2, name = (null)}
2016-07-06 17:30:00.860 threadDemo[1241:185626] a1a1 -> 完成
2016-07-06 17:30:02.134 threadDemo[1241:185642] a1s2 -> 完成
2016-07-06 17:30:02.134 threadDemo[1241:185642] a1a2 -> 开始<NSThread: 0x7fdbcae1a6a0>{number = 2, name = (null)}
2016-07-06 17:30:03.418 threadDemo[1241:185642] a1a2 -> 完成
其中a的意思是异步,s为同步。
上述例子表明:
1. 我们可以在block任务里嵌套任务
2. 每个子任务并不代表一个线程。
我们可以看出来,在并行队列中:
异步的block需要等待其前面一个同步的block做完才能开始,同步的block不需要等待其前面一个异步block可以和它同时开始,同步的block需要等待其前面一个同步的block做完才能开始。
几个异步block可以同时开始。
而任务运行的线程数目和任务没有关系,会在运行时由cpu调度。之前以为并行队列里多少任务就多少线程其实是错的,如果前面一个任务做完了,其线程会拿来执行后面的任务。就如上面的例子,只开了2个子线程。
推荐几篇好文章:
http://www.cnblogs.com/yjg2014/p/yjg.html
关于GCD与NSOperation的区别:
http://www.jianshu.com/p/d09e2638eb27
http://blog.youkuaiyun.com/q199109106q/article/details/8566222
———关于延时/定时的补充:————————-
//重复执行
-(void)someMethod{
static dispatch_source_t _timer;
//间隔还是60秒
uint64_t interval = 60 * NSEC_PER_SEC;
//创建一个专门执行timer回调的GCD队列
dispatch_queue_t queue = dispatch_queue_create("uploadScore", 0);
//创建Timer
_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
//使用dispatch_source_set_timer函数设置timer参数
dispatch_source_set_timer(_timer, dispatch_time(DISPATCH_TIME_NOW, 0), interval, 0);
//设置回调
dispatch_source_set_event_handler(_timer, ^()
{
[uploadscoreVC startUploadScore];
});
//dispatch_source默认是Suspended状态,通过dispatch_resume函数开始它
dispatch_resume(_timer);
}
—————————原文—————————————–
下面说下 iOS中延时的几种方法:
//非阻塞 执行一次
//delayMethod在dispatch_after指定的线程里执行
- (void)methodFourGCD{
__block GCDViewController *weakSelf = self;
dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC));
// dispatch_after(delayTime, dispatch_get_main_queue(), ^{
// [weakSelf delayMethod];
// });
dispatch_after(delayTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
[weakSelf delayMethod];
});
}
//阻塞 delayMethod在所在线程执行,所以最好不要放在主线程里
- (void)methodThreeSleep{
[NSThread sleepForTimeInterval:2.0];
[self delayMethod];
}
//非阻塞 delayMethod主线程执行,其他线程无效
- (void)methodTwoNSTimer{
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(delayMethod) userInfo:nil repeats:NO];
}
//非阻塞 delayMethod主线程执行,其他线程无效
- (void)methodOnePerformSelector{
[self performSelector:@selector(delayMethod) withObject:nil afterDelay:2.0];
}
NSTimer 可以用invalidate去取消,其他的暂无取消方法。
NSTimer还可以用设置fireDate的方法去暂停(distantFuture)和重启(sincenow)
关于用NSThread去创建一个子线程的几种方法:
NSThread *myThread = [[NSThread alloc]initWithTarget:self selector:@selector(startCount) object:nil];
[myThread start];
//静态方法创建
[NSThread detachNewThreadSelector:@selector(startCount) toTarget:self withObject:nil];
//隐式创建
[self performSelectorInBackground:@selector(startCount) withObject:nil];
其中detachNewThreadSelector即创建完立即start