zoukankan      html  css  js  c++  java
  • 多线程单线程,同步异步,并发并行,串行队列并行队列,看这里就对了

    多线程开发用了很久,但是一直没去深入了解。长久以来一直有一些迷惑。直到深入了解后,才发现了以前的理解有不少错误的地方。

    单线程等于同步,多线程等于异步

    • 这种理解很直观,毕竟只有一个线程怎么异步?

    Node.js表示不服,我就是单线程,我也能异步。谈一谈Node中的异步和单线程
    看完这篇文章我明白了单线程也能异步,把IO等耗时的操作比作烧水,我可以在这个时候切菜,这就是异步啊。
    等等,似乎有点不对,那io又谁来开启,又谁来通知cpu我已经结束了呢?
    Node.js异步IO的实现,这篇文章解决了我的疑惑。

    • Node.js里面只有自己写的代码是跑在主线程上,但是内部并不是单线程的,由C编写的底层开启了线程做IO操作。

    恍然大悟,我现在的理解就是,会有一个可运行的线程池在等待cpu的使用权。类似IO,网络请求这种耗时干等的操作,线程会放到需要等待的线程池中(阻塞),不会获取cpu的使用权,直到操作完成

    这个理解了,并发和并行就很容易了。

    • 每个线程获得cpu的使用权的时间就是一个时间片,用完了就必须要等下次了。时间片非常短,人根本意识不到,感觉就是并行的,但其实只是"伪并行",也就是并发。

    概念都讲结束了,现在可以谈谈iOS的多线程了。其实理论都一样,无非线程的获得,开启,结束等。但是iOS有个不同,他有GCD,那真是神器。
    关于GCD的串行队列,并行队列,一直以来都有一个错误的理解:

    队列就是线程,async就是另开线程,sync就是阻塞线程

    实践才能出真知,要想真明白,async,sync,串行队列,并行队列,主队列,还是要亲自测一下才行。

    • 主线程下,是否开启新线程
    //主队列
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"%@",[NSThread currentThread]);
    });
        
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"%@",[NSThread currentThread]);
    });
    
    //串行队列
    dispatch_queue_t ser_queue = dispatch_queue_create("串行", DISPATCH_QUEUE_SERIAL);
        
    dispatch_async(ser_queue, ^{
        NSLog(@"1-%@",[NSThread currentThread]);
    });
    
    dispatch_async(ser_queue, ^{
        NSLog(@"2-%@",[NSThread currentThread]);
    });
        
    dispatch_sync(ser_queue, ^{
        NSLog(@"3-%@",[NSThread currentThread]);
    });
    
    //并行队列
    dispatch_queue_t con_queue = dispatch_queue_create("并行", DISPATCH_QUEUE_CONCURRENT);
        
    dispatch_async(con_queue, ^{
        NSLog(@"1-%@",[NSThread currentThread]);
    });
    
    dispatch_async(con_queue, ^{
        NSLog(@"2-%@",[NSThread currentThread]);
    });
        
    dispatch_sync(con_queue, ^{
        NSLog(@"3-%@",[NSThread currentThread]);
    });
    
    • 非主线程下,异步是否新开线程
        dispatch_queue_t ser_queue = dispatch_queue_create("串行", DISPATCH_QUEUE_SERIAL);
        dispatch_queue_t con_queue = dispatch_queue_create("并行", DISPATCH_QUEUE_CONCURRENT);
    
        
        dispatch_async(ser_queue, ^{
            NSLog(@"1-%@",[NSThread currentThread]);
            dispatch_async(ser_queue, ^{
                NSLog(@"1-%@",[NSThread currentThread]);
            });
        });
        
        dispatch_async(ser_queue, ^{
            NSLog(@"2-%@",[NSThread currentThread]);
            dispatch_async(con_queue, ^{
                NSLog(@"2-%@",[NSThread currentThread]);
            });
        });
        
        dispatch_async(con_queue, ^{
            NSLog(@"3-%@",[NSThread currentThread]);
            dispatch_async(con_queue, ^{
                NSLog(@"3-%@",[NSThread currentThread]);
            });
        });
        
        dispatch_async(con_queue, ^{
            NSLog(@"4-%@",[NSThread currentThread]);
            dispatch_async(ser_queue, ^{
                NSLog(@"4-%@",[NSThread currentThread]);
            });
        });
    
        dispatch_async(ser_queue, ^{
            NSLog(@"5-%@",[NSThread currentThread]);
            dispatch_async(dispatch_get_main_queue(), ^{
                NSLog(@"5-%@",[NSThread currentThread]);
            });
        });
    
        dispatch_async(con_queue, ^{
            NSLog(@"6-%@",[NSThread currentThread]);
            dispatch_async(dispatch_get_main_queue(), ^{
                NSLog(@"6-%@",[NSThread currentThread]);
            });
        });
    
    • 非主线程下,同步是否新开线程
        dispatch_async(ser_queue, ^{
            NSLog(@"1-%@",[NSThread currentThread]);
            dispatch_sync(ser_queue, ^{
                NSLog(@"1-%@",[NSThread currentThread]);
            });
        });
        
        dispatch_async(ser_queue, ^{
            NSLog(@"2-%@",[NSThread currentThread]);
            dispatch_sync(con_queue, ^{
                NSLog(@"2-%@",[NSThread currentThread]);
            });
        });
    
        dispatch_async(con_queue, ^{
            NSLog(@"3-%@",[NSThread currentThread]);
            dispatch_sync(con_queue, ^{
                NSLog(@"3-%@",[NSThread currentThread]);
            });
        });
    
        dispatch_async(con_queue, ^{
            NSLog(@"4-%@",[NSThread currentThread]);
            dispatch_sync(ser_queue, ^{
                NSLog(@"4-%@",[NSThread currentThread]);
            });
        });
    
        dispatch_async(ser_queue, ^{
            NSLog(@"5-%@",[NSThread currentThread]);
            dispatch_sync(dispatch_get_main_queue(), ^{
                NSLog(@"5-%@",[NSThread currentThread]);
            });
        });
        
        dispatch_async(con_queue, ^{
            NSLog(@"6-%@",[NSThread currentThread]);
            dispatch_sync(dispatch_get_main_queue(), ^{
                NSLog(@"6-%@",[NSThread currentThread]);
            });
        });
    

    结论:
    结果就不贴出来了,还是自己亲自测下比较好。看看自己的想法和答案是否一致可是一件很快乐的事情。
    基本上覆盖了所有可能。感觉更像是面向队列来的,线程的调度是系统自己分配的。

    测下来感觉就是回答了两个问题:

    • async什么时候会新开线程
    • sync什么时候会导致死锁

    我的答案:

    • 主队列:一定会在主线程
    • 串行队列:async会开一条线程
    • 并行队列:async会开多条线程
    • 死锁:必须是串行队列,其次提交block所在队列和把block放进去的队列是同一个。
    • async不同的队列,基本上是在不同的线程上。(存疑)
    • 提交block的队列和block放进去的队列是同一个,不管串行并行,都在同一个线程上。(存疑)

    GCD是神器,还有好多需要学习的地方,推荐几篇经典的文章:
    GCD扫盲篇巧谈GCD
    GCD进阶篇
    死锁,图文并茂,清晰易懂

  • 相关阅读:
    ES6入门之Promise对象
    Iterator和ListIterator区别
    try_catch_return
    T-SQL查询进阶--详解公用表表达式(CTE)
    Node.js安装及环境配置之Windows篇
    Java中Lambda表达式的使用
    windows下redis 开机自启动
    IDEA快捷键(修改成eclipse版)+Templates
    oracle赋予一个用户具有查询另一个用户所有表数据
    sql触发器
  • 原文地址:https://www.cnblogs.com/stevenfukua/p/6545558.html
Copyright © 2011-2022 走看看