精华内容
下载资源
问答
  • 关于JS同步函数和异步函数

    千次阅读 2019-03-10 10:35:26
    关于JS中的同步函数和异步函数 自己个人的理解: 同步函数:同步函数是顺序执行的,如果这自上而下的过程很长,那么该线程就会一直挂起,知道函数返回,才能让该线程重新调度 异步函数:当该线程遇到譬如此类,就会执行下一...

    关于JS中的同步函数和异步函数
    自己个人的理解:
    同步函数:同步函数是顺序执行的,如果这自上而下的过程很长,那么该线程就会一直挂起,知道函数返回,才能让该线程重新调度
    异步函数:当该线程遇到譬如此类,就会执行下一条语句,那上一条语句应该怎么办呢?大概就是把这条语句交给了其他的线程处理吧,该线程处理完后就会把结果返回给回调函数,在回调函数中咱们就可以进行处理,一定要记住!!!POINT!!所以我经常忘记在回调函数中取数据导致有时候取出的数据是空…

    附带一个进程,线程,多线程的链接,忘了的时候来看看…

    https://www.cnblogs.com/fuchongjundream/p/3829508.html

    展开全文
  • 2)纯C语言,提供了非常多强大的函数 GCD的优势 1)GCD是苹果为多核的并行运算提出的解决方案。 2)GCD会自动利用更多的CPU内核(比如双核,四核)。 3)GCD会自动管理线程的生命周期(创建线程,调度任务)。 ...
    • 什么是GCD

        1)全称是Grand Central Dispatch,可译为“牛逼的中枢调度器”

        2)纯C语言,提供了非常多强大的函数

    • GCD的优势

        1)GCD是苹果为多核并行运算提出的解决方案。

        2)GCD会自动利用更多的CPU内核(比如双核,四核)。

        3)GCD会自动管理线程的生命周期(创建线程,调度任务)。

    • 任务和队列

        1)任务:执行什么操作

        2)队列:用来存放任务

    • GCD的使用就两个步骤

         1)定制任务(确定想做的事)

         2)将任务添加到队列(GCD会自动将队列中的任务取出,放到对应的线程中去执行; 任务的取出遵循队列的FIFO原则:先进先出,后进后出(栈是先进后出))

    • 执行任务

       GCD中有2个用来执行任务的常用函数

       1)  用同步的方式执行任务

        dispatch_sync(dispatch_queue_t  queue, dispatch_block_t block): queue: 队列  block: 任务

       2)用异步的方式执行任务

        dispatch_async(dispatch_queue_t  queue, dispatch_block_t block)

    • 同步和异步的区别

       1)同步:只能在当前的线程中执行任务,不具备开启新线程的能力

       2)异步:可以在新的线程中执行任务,具备开启新线程的能力

    • 队列的类型

        GCD的队列可以分为两大类型

        1. 并发队列

        1) 可以让多个任务并发同时执行(自动开启多个线程自动执行任务)

        2)并发功能只有在异步(dispatch_async)函数下才有效

        2. 串行队列

        1)让任务一个接一个的执行(一个任务执行完毕后,再执行下一个任务)

    • 容易混淆的术语

           有四个术语比较容易混淆:同步,异步,并发,串行

         1. 同步和异步的主要区别:能不能开启新的线程

         1)同步:只是在当前线程中执行任务,不具备开启新线程的能力

         2)异步:可以在新的线程中执行,具备开启新线程的能力

         2. 并发和串行的主要区别:任务的执行方式

          1)并发:允许多个任务并发(同时)执行

          2)串行:一个任务执行完毕后,再执行下一个任务


    GCD的基本使用

    #import "ViewController.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    #pragma mark ----------------------
    #pragma Events
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
    //    [NSThread detachNewThreadSelector:@selector(syncMain) toTarget:self withObject:nil];
        
        [self asyncConcurrent];
    }
    
    #pragma mark ----------------------
    #pragma Methods
    //异步函数+并发队列:会开启多条线程,队列中的任务是并发执行
    //注意:并不是有多少个任务就开启多少个线程,是由系统内部决定的
    -(void)asyncConcurrent
    {
        //1.创建队列
        /*
         第一个参数:C语言的字符串,标签
         第二个参数:队列的类型
            DISPATCH_QUEUE_CONCURRENT:并发
            DISPATCH_QUEUE_SERIAL:串行
         */
        //dispatch_queue_t queue = dispatch_queue_create("com.www.download", DISPATCH_QUEUE_CONCURRENT);
        
        //获得全局并发队列
        /*
         第一个参数:优先级
         第二个参数:
         */
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        
        NSLog(@"---satrt----");
        
        //2.1>封装任务2>添加任务到队列中
        /*
         第一个参数:队列
         第二个参数:要执行的任务
         */
        dispatch_async(queue, ^{
            NSLog(@"download1----%@",[NSThread currentThread]);
        });
        
        dispatch_async(queue, ^{
            NSLog(@"download2----%@",[NSThread currentThread]);
        });
        
        dispatch_async(queue, ^{
            NSLog(@"download3----%@",[NSThread currentThread]);
        });
        
         NSLog(@"---end----");
    }
    
    //异步函数+串行队列:会开线程,开一条线程,队列中的任务是串行执行的
    -(void)asyncSerial
    {
        //1.创建队列
        dispatch_queue_t queue = dispatch_queue_create("download", DISPATCH_QUEUE_SERIAL);
    
        //2.封装操作
        dispatch_async(queue, ^{
            NSLog(@"download1----%@",[NSThread currentThread]);
        });
        
        dispatch_async(queue, ^{
            NSLog(@"download2----%@",[NSThread currentThread]);
        });
        
        dispatch_async(queue, ^{
            NSLog(@"download3----%@",[NSThread currentThread]);
        });
    }
    
    //同步函数+并发队列:不会开线程,任务是串行执行的
    -(void)syncConcurrent
    {
        //1.创建队列
        dispatch_queue_t queue = dispatch_queue_create("com.www.download", DISPATCH_QUEUE_CONCURRENT);
        
        NSLog(@"---start---");
        //2.封装任务
        dispatch_sync(queue, ^{
            NSLog(@"download1----%@",[NSThread currentThread]);
        });
        
        dispatch_sync(queue, ^{
            NSLog(@"download2----%@",[NSThread currentThread]);
        });
        
        dispatch_sync(queue, ^{
            NSLog(@"download3----%@",[NSThread currentThread]);
        });
        
         NSLog(@"---end---");
    }
    
    //同步函数+串行队列:不会开线程,任务是串行执行的
    -(void)syncSerial
    {
        //1.创建队列
        dispatch_queue_t queue = dispatch_queue_create("com.www.download", DISPATCH_QUEUE_SERIAL);
        
        //2.封装任务
        dispatch_sync(queue, ^{
            NSLog(@"download1----%@",[NSThread currentThread]);
        });
        
        dispatch_sync(queue, ^{
            NSLog(@"download2----%@",[NSThread currentThread]);
        });
        
        dispatch_sync(queue, ^{
            NSLog(@"download3----%@",[NSThread currentThread]);
        });
    }
    
    //异步函数+主队列:所有任务都在主线程中执行,不会开线程
    -(void)asyncMain
    {
        //1.获得主队列
        dispatch_queue_t queue = dispatch_get_main_queue();
    
        //2.异步函数
        dispatch_async(queue, ^{
            NSLog(@"download1----%@",[NSThread currentThread]);
        });
        
        dispatch_async(queue, ^{
            NSLog(@"download2----%@",[NSThread currentThread]);
        });
        
        dispatch_async(queue, ^{
            NSLog(@"download3----%@",[NSThread currentThread]);
        });
    }
    
    //同步函数+主队列:死锁
    //注意:如果该方法在子线程中执行,那么所有的任务在主线程中执行,不会死锁
    -(void)syncMain
    {
        //1.获得主队列
        dispatch_queue_t queue = dispatch_get_main_queue();
        
        NSLog(@"start----");
        //2.同步函数
        //同步函数:立刻马上执行,如果我没有执行完毕,那么后面的也别想执行
        //异步函数:如果我没有执行完毕,那么后面的也可以执行
        dispatch_sync(queue, ^{
            NSLog(@"download1----%@",[NSThread currentThread]);
        });
        
        dispatch_sync(queue, ^{
            NSLog(@"download2----%@",[NSThread currentThread]);
        });
        
        dispatch_sync(queue, ^{
            NSLog(@"download3----%@",[NSThread currentThread]);
        });
        
        NSLog(@"end---");
    }
    @end

       


    各种队列的执行效果

     注意:使用sync(同步)函数往当前串行队列中添加任务,会卡住当前的串行队列,造成死锁


    GCD实现线程间通信(子线程耗时下载,主线程更新UI)

    • 从子线程回到主线程

    dispatch_async(

           dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

            // 执行耗时的异步操作...

            dispatch_async(dispatch_get_main_queue(), ^{

             // 回到主线程,执行UI刷新操作

            });

    });

    #import "ViewController.h"
    
    @interface ViewController ()
    @property (weak, nonatomic) IBOutlet UIImageView *imageView;
    
    @end
    
    @implementation ViewController
    
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
        //1.创建子线程下载图片
        //DISPATCH_QUEUE_PRIORITY_DEFAULT 0
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
           
            //1.1 确定url
            NSURL *url = [NSURL URLWithString:@"http://a.hiphotos.baidu.com/zhidao/wh%3D450%2C600/sign=da0ec79c738da9774e7a8e2f8561d42f/c83d70cf3bc79f3d6842e09fbaa1cd11738b29f9.jpg"];
            
            //1.2 下载二进制数据到本地
           NSData *imageData =  [NSData dataWithContentsOfURL:url];
            
            //1.3 转换图片
            UIImage *image = [UIImage imageWithData:imageData];
            
            NSLog(@"download----%@",[NSThread currentThread]);
            
            //更新UI
    //        dispatch_async(dispatch_get_main_queue(), ^{
            dispatch_sync(dispatch_get_main_queue(), ^{
                self.imageView.image = image;
                 NSLog(@"UI----%@",[NSThread currentThread]);
            });
            
        });
    }
    
    @end

    GCD常用函数

    • 延时执行

        1)调用NSObject的方法

    • [self performSelector:@selector(run) withObject:nil afterDelay:2.0];

      // 2秒后再调run方法

         2)使用GCD函数

    • dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

          // 2秒后执行这里的代码...

      });

          3)使用NSTimer

    • [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(test) userInfo:nil repeats:NO];

    • 4)一次性代码

    • //使用dispatch_once函数能保证某段代码在程序运行过程中只被执行1次
      static dispatch_once_t onceToken;
      dispatch_once(&onceToken, ^{
          // 只执行1次的代码(这里面默认是线程安全的)
      });

      5)代码示例

    #import "ViewController.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
        [self once];
    }
    
    //延迟执行
    -(void)delay
    {
        NSLog(@"start-----");
        
        //1. 延迟执行的第一种方法
        //[self performSelector:@selector(task) withObject:nil afterDelay:2.0];
        
        //2.延迟执行的第二种方法
        //[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(task) userInfo:nil repeats:YES];
        
        //3.GCD
    //    dispatch_queue_t queue = dispatch_get_main_queue();
         dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
        /*
         第一个参数:DISPATCH_TIME_NOW 从现在开始计算时间
         第二个参数:延迟的时间 2.0 GCD时间单位:纳秒
         第三个参数:队列
         */
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), queue, ^{
            NSLog(@"GCD----%@",[NSThread currentThread]);
        });
    
    }
    
    //一次性代码
    //不能放在懒加载中的,应用场景:单例模式
    -(void)once
    {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            NSLog(@"---once----");
        });
    }
    
    -(void)task
    {
        NSLog(@"task----%@",[NSThread currentThread]);
    }
    @end

    GCD栅栏函数

    • GCD中还有个用来执行任务的函数:

           dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);

           在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行

    • 这个queue不能是全局的并发队列
    #import "ViewController.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
        
        //0.获得全局并发队列
        //栅栏函数不能使用全局并发队列,只能使用自己创建的并发队列
        //dispatch_queue_t queue =  dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        dispatch_queue_t queue = dispatch_queue_create("download", DISPATCH_QUEUE_CONCURRENT);
        
        //1.异步函数
        dispatch_async(queue, ^{
           
            for (NSInteger i = 0; i<100; i++) {
                NSLog(@"download1-%zd-%@",i,[NSThread currentThread]);
            }
            
        });
        
        dispatch_async(queue, ^{
            
            for (NSInteger i = 0; i<100; i++) {
                NSLog(@"download2-%zd-%@",i,[NSThread currentThread]);
            }
        });
        
        
        //栅栏函数
        dispatch_barrier_async(queue, ^{
           
            NSLog(@"+++++++++++++++++++++++++++++");
        });
        
        dispatch_async(queue, ^{
            
            for (NSInteger i = 0; i<100; i++) {
                NSLog(@"download3-%zd-%@",i,[NSThread currentThread]);
            }
        });
        
        dispatch_async(queue, ^{
            
            for (NSInteger i = 0; i<100; i++) {
                NSLog(@"download4-%zd-%@",i,[NSThread currentThread]);
            }
        });
    }
    
    @end
    

    GCD快速迭代

    • 使用dispatch_apply函数能进行快速迭代遍历
    dispatch_apply(10, dispatch_get_global_queue(0, 0), ^(size_t index){
    
        // 执行10次代码,index顺序不确定
    
    });

    剪切文件代码示例:

    #import "ViewController.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
        [self moveFileWithGCD];
    }
    
    -(void)forDemo
    {
        //同步,在主线程串行
        for (NSInteger i = 0; i<10; i++) {
            NSLog(@"%zd---%@",i,[NSThread currentThread]);
        }
    }
    
    //开子线程和主线程一起完成遍历任务,任务的执行时并发的
    -(void)applyDemo
    {
        /*
         第一个参数:遍历的次数
         第二个参数:队列(并发队列)
         第三个参数:index 索引
         */
        dispatch_apply(10, dispatch_get_global_queue(0, 0), ^(size_t index) {
            NSLog(@"%zd---%@",index,[NSThread currentThread]);
        });
    }
    
    //使用for循环
    -(void)moveFile
    {
        //1.拿到文件路径
        NSString *from = @"/Users/Alan/Desktop/from";
        
        //2.获得目标文件路径
        NSString *to = @"/Users/Alan/Desktop/to";
        
        //3.得到目录下面的所有文件
        NSArray *subPaths = [[NSFileManager defaultManager] subpathsAtPath:from];
        
        NSLog(@"%@",subPaths);
        //4.遍历所有文件,然后执行剪切操作
        NSInteger count = subPaths.count;
        
        for (NSInteger i = 0; i< count; i++) {
            
            //4.1 拼接文件的全路径
           // NSString *fullPath = [from stringByAppendingString:subPaths[i]];
            //在拼接的时候会自动添加/
            NSString *fullPath = [from stringByAppendingPathComponent:subPaths[i]];
            NSString *toFullPath = [to stringByAppendingPathComponent:subPaths[i]];
            
            NSLog(@"%@",fullPath);
            //4.2 执行剪切操作
            /*
             第一个参数:要剪切的文件在哪里
             第二个参数:文件应该被存到哪个位置
             */
            [[NSFileManager defaultManager]moveItemAtPath:fullPath toPath:toFullPath error:nil];
            
            NSLog(@"%@---%@--%@",fullPath,toFullPath,[NSThread currentThread]);
        }
    }
    
    -(void)moveFileWithGCD
    {
        //1.拿到文件路径
        NSString *from = @"/Users/Alan/Desktop/from";
        
        //2.获得目标文件路径
        NSString *to = @"/Users/Alan/Desktop/to";
        
        //3.得到目录下面的所有文件
        NSArray *subPaths = [[NSFileManager defaultManager] subpathsAtPath:from];
        
        NSLog(@"%@",subPaths);
        //4.遍历所有文件,然后执行剪切操作
        NSInteger count = subPaths.count;
        
        dispatch_apply(count, dispatch_get_global_queue(0, 0), ^(size_t i) {
            //4.1 拼接文件的全路径
            // NSString *fullPath = [from stringByAppendingString:subPaths[i]];
            //在拼接的时候会自动添加/
            NSString *fullPath = [from stringByAppendingPathComponent:subPaths[i]];
            NSString *toFullPath = [to stringByAppendingPathComponent:subPaths[i]];
            
            NSLog(@"%@",fullPath);
            //4.2 执行剪切操作
            /*
             第一个参数:要剪切的文件在哪里
             第二个参数:文件应该被存到哪个位置
             */
            [[NSFileManager defaultManager]moveItemAtPath:fullPath toPath:toFullPath error:nil];
            
            NSLog(@"%@---%@--%@",fullPath,toFullPath,[NSThread currentThread]);
    
        });
    }
    @end

    GCD队列组

    • 队列组使用情况

         1)分别异步执行多个耗时的操作

         2)等多个异步操作都执行完毕后,再回到主线程执行操作

        3)拦截通知,当队列组中所有的任务都执行完毕的时候回进入到下面的方法,异步的,不会阻塞线程

    dispatch_group_t group =  dispatch_group_create();
    
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    
        // 执行1个耗时的异步操作
    
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    
        // 执行1个耗时的异步操作
    
    });
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    
        // 等前面的异步操作都执行完毕后,回到主线程...
    
    });

     下载两张图片合并成一张代码示例:

    #import "ViewController.h"
    
    @interface ViewController ()
    /** 图片1 */
    @property (nonatomic, strong) UIImage *image1;
    /** 图2 */
    @property (nonatomic, strong) UIImage *image2;
    
    @property (weak, nonatomic) IBOutlet UIImageView *imageView;
    @end
    
    @implementation ViewController
    
    #pragma mark ----------------------
    #pragma mark Events
    
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
        [self test];
    }
    #pragma mark ----------------------
    #pragma mark Methods
    -(void)group1
    {
        //1.创建队列
        dispatch_queue_t queue =dispatch_get_global_queue(0, 0);
        
        //2.创建队列组
        dispatch_group_t group = dispatch_group_create();
        
        //3.异步函数
        /*
         1)封装任务
         2)把任务添加到队列中
         dispatch_async(queue, ^{
         NSLog(@"1----%@",[NSThread currentThread]);
         });
         */
        /*
         1)封装任务
         2)把任务添加到队列中
         3)会监听任务的执行情况,通知group
         */
        dispatch_group_async(group, queue, ^{
            NSLog(@"1----%@",[NSThread currentThread]);
        });
        
        
        dispatch_group_async(group, queue, ^{
            NSLog(@"2----%@",[NSThread currentThread]);
        });
        
        dispatch_group_async(group, queue, ^{
            NSLog(@"3----%@",[NSThread currentThread]);
        });
        
        //拦截通知,当队列组中所有的任务都执行完毕的时候回进入到下面的方法,异步的,不会阻塞线程
        dispatch_group_notify(group, queue, ^{
            
            NSLog(@"-------dispatch_group_notify-------");
        });
        
            NSLog(@"----end----");
    
    }
    
    -(void)group2
    {
        //1.创建队列
        dispatch_queue_t queue =dispatch_get_global_queue(0, 0);
        
        //2.创建队列组
        dispatch_group_t group = dispatch_group_create();
        
        //3.在该方法后面的异步任务会被纳入到队列组的监听范围,进入群组
        //dispatch_group_enter|dispatch_group_leave 必须要配对使用
        dispatch_group_enter(group);
        
        dispatch_async(queue, ^{
            NSLog(@"1----%@",[NSThread currentThread]);
            
            //离开群组
            dispatch_group_leave(group);
        });
        
        dispatch_group_enter(group);
        
        dispatch_async(queue, ^{
            NSLog(@"2----%@",[NSThread currentThread]);
        
            //离开群组
            dispatch_group_leave(group);
        });
        
        
        //拦截通知
        //问题?该方法是阻塞的吗?  内部本身是异步的
    //    dispatch_group_notify(group, queue, ^{
    //        NSLog(@"-------dispatch_group_notify-------");
    //    });
        
        //等待.死等. 直到队列组中所有的任务都执行完毕之后才能执行
        //阻塞的,会阻塞线程
        dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
        NSLog(@"----end----");
        
    }
    
    -(void)group3
    {
        /*
         1.下载图片1 开子线程
         2.下载图片2 开子线程
         3.合成图片并显示图片 开子线程
         */
        
        //-1.获得队列组
        dispatch_group_t group = dispatch_group_create();
        
        //0.获得并发队列
        dispatch_queue_t queue =  dispatch_get_global_queue(0, 0);
        
        // 1.下载图片1 开子线程
        dispatch_group_async(group, queue,^{
            
            NSLog(@"download1---%@",[NSThread currentThread]);
            //1.1 确定url
            NSURL *url = [NSURL URLWithString:@"http://www.qbaobei.com/tuku/images/13.jpg"];
            
            //1.2 下载二进制数据
            NSData *imageData = [NSData dataWithContentsOfURL:url];
            
            //1.3 转换图片
            self.image1 = [UIImage imageWithData:imageData];
        });
        
        // 2.下载图片2 开子线程
         dispatch_group_async(group, queue,^{
             
             NSLog(@"download2---%@",[NSThread currentThread]);
             //2.1 确定url
            NSURL *url = [NSURL URLWithString:@"http://pic1a.nipic.com/2008-09-19/2008919134941443_2.jpg"];
            
            //2.2 下载二进制数据
            NSData *imageData = [NSData dataWithContentsOfURL:url];
            
            //2.3 转换图片
            self.image2 = [UIImage imageWithData:imageData];
        });
    
        //3.合并图片
        //主线程中执行
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
           
            NSLog(@"combie---%@",[NSThread currentThread]);
            //3.1 创建图形上下文
            UIGraphicsBeginImageContext(CGSizeMake(200, 200));
            
            //3.2 画图1
            [self.image1 drawInRect:CGRectMake(0, 0, 200, 100)];
            self.image1 = nil;
            
            //3.3 画图2
            [self.image2 drawInRect:CGRectMake(0, 100, 200, 100)];
            self.image2 = nil;
            
            //3.4 根据上下文得到一张图片
            UIImage *image =  UIGraphicsGetImageFromCurrentImageContext();
            
            //3.5 关闭上下文
            UIGraphicsEndImageContext();
            
            //3.6 更新UI
    //        dispatch_async(dispatch_get_main_queue(), ^{
            
                NSLog(@"UI----%@",[NSThread currentThread]);
                self.imageView.image = image;
    //        });
        });
        
    //    dispatch_release(group)
    }
    
    -(void)test
    {
       // dispatch_async(<#dispatch_queue_t queue#>, <#^(void)block#>)
        //区别:封装任务的方法(block--函数)
        /*
         第一个参数:队列
         第二个参数:参数
         第三个参数:要调用的函数的名称
         */
        dispatch_async_f(dispatch_get_global_queue(0, 0), NULL, task);
        dispatch_async_f(dispatch_get_global_queue(0, 0), NULL, task);
        dispatch_async_f(dispatch_get_global_queue(0, 0), NULL, task);
    }
    
    void task(void *param)
    {
        NSLog(@"%s---%@",__func__,[NSThread currentThread]);
    }
    
    @end

    GCD单例模式

    • 单例模式的作用

       1)可以保证在程序运行过程,一个类只有一个实例,而且该实例易于供外界访问

       2)从而方便地控制了实例个数,并节约系统资源

    • 单例模式的使用场合
    • 在整个应用程序中,共享一份资源(这份资源只需要创建初始化1次)
    • ARC中,单例模式的实现

        1)在.m中保留一个全局的static的实例

    static id _instance;

         2)重写allocWithZone:方法,在这里创建唯一的实例(注意线程安全)

    + (instancetype)allocWithZone:(struct _NSZone *)zone
    
    {
    
        static dispatch_once_t onceToken;
    
        dispatch_once(&onceToken, ^{
    
            _instance = [super allocWithZone:zone];
    
        });
    
        return _instance;
    
    }
    • 提供1个类方法让外界访问唯一的实例
    + (instancetype)sharedInstance
    
    {
    
        static dispatch_once_t onceToken;
    
        dispatch_once(&onceToken, ^{
    
            _instance = [[self alloc] init];
    
        });
    
        return _instance;
    
    }

     

    • 实现copyWithZone:方法
    - (id)copyWithZone:(struct _NSZone *)zone
    
    {
    
        return _instance;
    
    }

     具体单例代码:

    AlanTool.h

    #import <Foundation/Foundation.h>
    
    @interface AlanTool : NSObject<NSCopying, NSMutableCopying>
    
    //类方法
    //1.方便访问
    //2.标明身份
    //3.注意:share+类名|default + 类名 | share | default | 类名
    +(instancetype)shareTool;
    @end

    AlanTool.m

    #import "AlanTool.m"
    
    @implementation AlanTool
    
    //0.提供全局变量
    static AlanTool *_instance;
    
    //1.alloc-->allocWithZone
    +(instancetype)allocWithZone:(struct _NSZone *)zone
    {
        //加互斥锁解决多线程访问安全问题
    //    @synchronized(self) {
    //        if (_instance == nil) {
    //            _instance = [super allocWithZone:zone];
    //        }
    //    }
        
        //本身就是线程安全的
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _instance = [super allocWithZone:zone];
        });
        
        return _instance;
    }
    
    //2.提供类方法
    +(instancetype)shareTool
    {
        //1
        //return [[self alloc]init];
        //2
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _instance = [super allocWithZone:zone];
        });
        
        return _instance;
    }
    
    //3.严谨
    -(id)copyWithZone:(NSZone *)zone
    {
        return _instance;
    }
    
    -(id)mutableCopyWithZone:(NSZone *)zone
    {
        return _instance;
    }
    
    #if __has_feature(objc_arc)
    //条件满足 ARC
    #else
    // MRC
    -(void)release
    {
        
    }
    
    -(instancetype)retain
    {
        return _instance;
    }
    
    //习惯
    -(NSUInteger)retainCount
    {
        return MAXFLOAT;
    }
    
    #endif
    
    @end

    通过宏实现GCD单例模式

    #define SingleH(name) +(instancetype)share##name;
    
    #if __has_feature(objc_arc)
    //条件满足 ARC
    #define SingleM(name) static id _instance;\
    +(instancetype)allocWithZone:(struct _NSZone *)zone\
    {\
    static dispatch_once_t onceToken;\
    dispatch_once(&onceToken, ^{\
    _instance = [super allocWithZone:zone];\
    });\
    \
    return _instance;\
    }\
    \
    +(instancetype)share##name\
    {\
    return [[self alloc]init];\
    }\
    \
    -(id)copyWithZone:(NSZone *)zone\
    {\
    return _instance;\
    }\
    \
    -(id)mutableCopyWithZone:(NSZone *)zone\
    {\
    return _instance;\
    }
    
    #else
    //MRC
    #define SingleM(name) static id _instance;\
    +(instancetype)allocWithZone:(struct _NSZone *)zone\
    {\
    static dispatch_once_t onceToken;\
    dispatch_once(&onceToken, ^{\
    _instance = [super allocWithZone:zone];\
    });\
    \
    return _instance;\
    }\
    \
    +(instancetype)share##name\
    {\
    return [[self alloc]init];\
    }\
    \
    -(id)copyWithZone:(NSZone *)zone\
    {\
    return _instance;\
    }\
    \
    -(id)mutableCopyWithZone:(NSZone *)zone\
    {\
    return _instance;\
    }\
    -(oneway void)release\
    {\
    }\
    \
    -(instancetype)retain\
    {\
        return _instance;\
    }\
    \
    -(NSUInteger)retainCount\
    {\
        return MAXFLOAT;\
    }
    #endif
    

     

    展开全文
  • 同步函数异步函数

    千次阅读 2019-11-01 01:09:57
    定义:同步和异步关注的是消息通信机制(synchronous communication/ asynchronous communication)。从程序同步,就是调用方发起某个调用后,调用方得等待这个调用返回结果才能继续往下执行。异步,和同步相反 调用方...

    同步、异步概念

    定义:同步和异步关注的是消息通信机制 (synchronous communication/ asynchronous communication)。从程序同步,就是调用方发起某个调用后,调用方得等待这个调用返回结果才能继续往下执行。异步,和同步相反  调用方不会等待调用返回结果,而是在调用发出后,调用者继续执行后续操作,被调用者通过某种反馈机制来通知调用者,比如说监听被调用者的状态、被调用者执行完成后主动发出通知告知调用者或者通过回调的方式。

    同步与异步的区别

    同步:所有的操作都做完,才返回结果给用户。比如说,服务器端接收一个客户端的请求连接,建立连接后,Server处理Client的请求操作(如数据处理、读写操作等),Server在处理请求操作过程中,无法在响应其他客户端的连接,必须等到Server端处理完当前客户端的请求业务并返回处理结果给Client,两者断开连接后,Server才能处理下一个Client的连接请求。这个过程就是消息同步处理机制。

    异步:不需要等所有操作都做完,就可以继续执行其他的操作。上面的例子,如果是异步通信机制的话,Server与一个Client建立连接后,它把这个Client的业务请求通过缓存机制(如消息队列,先将请求消息放入消息队列中)交给其他的工作线程(工作线程可以通过线程池技术来实现)处理,Server可以继续接受其他客户端的连接请求,当某个客户端的业务请求处理完成时,通过某种反馈机制通知Server,然后Server把处理结果返回给Client端,然后断开连接。这个过程就是消息异步处理机制,这样的好处就是Server端可以响应高并发的连接请求,把连接请求和消息处理独立开来,能够提供系统的响应速度和数据处理的高效性。

    上面是从服务端的解读解读的,若是从客户端的角度谈同步,当客户端发送req请求给服务端,在等待服务端的resp响应应答时,客户端不能做其他的事情。当服务端处理完了客户端的请求业务后才返回resp应答消息给客户端。这样的话客户端需要一直等待。用户使用起来会很不友好。

    同步函数:当函数被调用时,直到函数把所要做的事情全部做完了才返回。对于调用者来说,调用者必须等到函数调用返回时才能继续后续的执行。

    异步函数:当函数被调用时,该函数会立即返回尽管该函数规定的操作任务可能还没有完成。异步函数的调用更像是一个消息传递过程,被调函数接收到调用者传进来的参数后,会把它放入消息队列中或者共享内存中,然后函数返回。真正的消息处理过程是在另一个线程中完成的,调用者不需要去等待这个消息处理结果,它可以去执行其他的任务。

    从客户端的角度来说的话,当客户端发送req请求给服务端时,在等待服务端应答响应时,客户端可以继续做其他的事情,这样节约了时间,提高了效率。

    同步函数执行过程

    同步调用:当调用方法执行完成后并返回结果,主调函数才能继续执行后续代码 。

    异步函数执行过程

    异步调用:可以参考ajax,主调函数调用方法后不会等到sum方法执行完成,而是继续执行后续代码。sum方法执行完成后主要通过状态通知主线程,或者通过回调方式处理这次异步方法执行的结果。

    同步异步与阻塞非阻塞不能混为一谈

    阻塞和非阻塞 强调的是程序在等待调用结果(消息,返回值)时的状态.  阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。 对于同步调用来说,很多时候当前线程还是激活的状态,只是从逻辑上当前函数没有返回而已,即同步等待时什么都不干,白白占用着资源。

    同步和异步 强调的是消息通信机制 (synchronous communication/ asynchronous communication)。所谓同步,就是在发出一个"调用"时,在没有得到结果之前,该“调用”就不返回。但是一旦调用返回,就得到返回值了。换句话说,就是由“调用者”主动等待这个“调用”的结果。而异步则是相反,"调用"在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步调用发出后,调用者不会立刻得到结果。而是在"调用"发出后,"被调用者"通过状态、通知来通知调用者,或通过回调函数处理这个调用。

    参考

    同步函数与异步函数

    同步(Synchronous)和异步(Asynchronous)

     

    展开全文
  • // // ViewController.m ...// 1124GCD多线程同步异步函数和并发串行队列 // // Created by weibiao on 15/11/24. // Copyright © 2015年 weibiao. All rights reserved. // #import "ViewController.h

    //

    //  ViewController.m

    //  1124GCD多线程同步异步函数和并发串行队列

    //

    //  Created by weibiao on 15/11/24.

    //  Copyright © 2015 weibiao. All rights reserved.

    //


    #import "ViewController.h"


    @interface ViewController ()


    @end


    @implementation ViewController


    - (void)viewDidLoad {

        [superviewDidLoad];

        

        [selfsyncGlobalQueue];

    //    [self asyncGlobalQueue];

    //    [self asyncSerialQueue];

    //    [self syncSerialQueue];

    }


    // 异步函数,执行串行队列,只会创建一条线程

    /**

     *  会创建1条线程

     */

    - (void)asyncSerialQueue {

        dispatch_queue_t queue =dispatch_queue_create("WBO",NULL);

        dispatch_async(queue, ^{

            NSLog(@"下载图片A----%@",[NSThreadcurrentThread]);

        });

        dispatch_async(queue, ^{

            NSLog(@"下载图片B----%@",[NSThreadcurrentThread]);

        });

        dispatch_async(queue, ^{

            NSLog(@"下载图片C----%@",[NSThreadcurrentThread]);

        });

    }


    // 异步函数,执行并发队列,会创建多条队列

    /**

     *  会创建3条线程

     */

    - (void)asyncGlobalQueue {

        dispatch_queue_t queue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

        dispatch_async(queue, ^{

            NSLog(@"下载图片A----%@",[NSThreadcurrentThread]);

        });

        dispatch_async(queue, ^{

            NSLog(@"下载图片B----%@",[NSThreadcurrentThread]);

        });

        dispatch_async(queue, ^{

            NSLog(@"下载图片C----%@",[NSThreadcurrentThread]);

        });

    }

    // 同步函数,执行串行队列,不会创建线程,在主线程中执行操作

    /**

     *  不会创建新的线程

     */

    - (void)syncSerialQueue {

        dispatch_queue_t queue =dispatch_queue_create("WB",NULL);

        dispatch_sync(queue, ^{

            NSLog(@"下载图片A----%@",[NSThreadcurrentThread]);

        });

        dispatch_sync(queue, ^{

            NSLog(@"下载图片B----%@",[NSThreadcurrentThread]);

        });

        dispatch_sync(queue, ^{

            NSLog(@"下载图片C----%@",[NSThreadcurrentThread]);

        });

    }

    // 同步函数,执行并发队列,不会创建队列

    /**

     *  不会创建新的线程

     */

    - (void)syncGlobalQueue {

        dispatch_queue_t queue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

        dispatch_sync(queue, ^{

            NSLog(@"下载图片A----%@",[NSThreadcurrentThread]);

        });

        dispatch_sync(queue, ^{

            NSLog(@"下载图片B----%@",[NSThreadcurrentThread]);

        });

        dispatch_sync(queue, ^{

            NSLog(@"下载图片C----%@",[NSThreadcurrentThread]);

        });

    }

    /**

     *  同步函数没有开线程的能力

     */

    @end


    展开全文
  • JS中的同步回调函数和异步回调函数
  • 一、函数的定义方式 函数声明: function 函数名() { ...同步异步 同步:符合咱们人的认知习惯,一行一行往下按照代码顺序执行,如果前面代码没有执行完,不会执行 缺点:容易导致代码阻塞 异
  • 同步回调函数: 理解:立即执行,完全执行完才结束,不会放到回调队列中 例子:数组遍历相关的函数回调,forEach、Promise的excutor函数 ...异步回调函数: 理解:不会立即执行,会放在回调队列中将.
  • 同步函数异步

    2014-01-24 11:33:00
    先说下异步(Asynchronous)多线程(Multi-threading)的区别:异步是相对与同步来说的,一般来说意味着非阻塞;异步在具体实现上是用多线程来实现的,但好处是你不用操心管理多线程,它给你封装了一个干净的...
  • 回调函数回调函数一般是在封装接口的时候,回调显得特别重要,我们首先假设有两个程序员在写代码,A程序员写底层驱动接口,B程序员写上层应用程序,然而此时底层驱动接口A有一个数据d需要传输给B,此时有两种方式:1...
  • 在进行窗口的resize、scroll,输入框内容校验等操作时,如果事件处理函数调用的频率无限制,会加重浏览器的负担,导致用户体验非常糟糕。此时我们可以采用debounce(防抖)throttle(节流)的方式来减少调用频率,...
  • 同步函数异步函数依据微软的MSDN上的解说:(1)同步函数:当一个函数是同步执行时,那么当该函数被调用时不会立即返回,直到该函数所要做的事情全都做完了才返回。(2)异步函数:如果一个异步函数被调用时,该...
  • 之前一直不是太懂async/await/Promise之间的关系,以及怎么使用,碰到同步执行和异步执行一起的函数就给同步函数加个setTimeout让他变成异步,可是,有时候请求后端数据延迟,还是会先执行了setTimeout包裹的函数 ...
  • 这里说两种方式,官网的上的是一样的: 第一种使用: async+ 立即执行函数 <div>方法一:async ()() 立即执行函数: {{doAsyncData.desc}}</div> doAsync () { const f = () => { return 'my '...
  • 将执行模式分成2种: 同步模式和异步模式 同步模式: 排队去执行,等这个任务结束才会去执行下一个任务 异步模式:多个任务同时执行,不会去等待这个任务结束才开始下一个任务 单线程的javaScript 语言就无法同时处理...
  • 同步和异步回调函数

    2020-07-18 03:40:37
    同步回调函数 let arr = [1,2,3,4,5,6]; arr.forEach(item=>{ console.log(item); }); console.log('end'); console.log是最后打印的,则成为同步回调 异步回调函数 setTimeout(()=>{ console.log('...
  • 异步回调函数注:JS中的同步异步和现实生活的正好相反。 其中同步回调函数是要等到回调函数都执行完成后才能进行接下来的操作,也就是说是阻塞式运行 同步回调函数示例 function waitFi...
  • 同步异步函数

    2019-10-14 21:01:07
    async 在函数前添加async是一个异步执行的函数, 使用await调用的函数,必须是一个返回promise对象的函数函数执行完成后,返回的结果就是.then(data)中的参数, asyncawait仅仅是Promise的一个语法糖,表面上看...
  • JS的异步和同步函数

    千次阅读 2019-08-20 14:49:09
    好久没有写博客了,从7月1日我正式从电子工程师(其实就是写单片机程序的)转为了前端开发(萌新),新工作加班较多,一些知识也没有放在博客上,今天遇到了同步和异步的问题,作为一个新的开始,重新记录。...
  • 一般而言,回调函数的形式为callback(err, res),即第一个参数是错误,第二个参数是所得的结果,我们遵从这个习惯 ...1. 接受异步函数的返回值与异常处理 同步函数的写法 var func = function() { try { var r
  • 同步请求和异步请求的区别同步是指:发送方发出数据后,等接收方发回响应以后才发下一个数据包的通讯方式。异步是指:发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式。即同步就是一个任务的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,162
精华内容 2,064
关键字:

同步函数和异步函数