IOS GCD 使用 (二)

LeRobot SO-ARM100 学习笔记(2) diffusion module 对 lerobot 中的 diffusion policy 进行基本的代码阅读 阅读详情
 上一节,主要介绍了GCD的基本的概念,这节将用代码深入详细介绍GCD的使用。

一  使用介绍

   GCD的使用主要分为三步:创建代码块;选择或创建合适的分发队列;(同步、异步方式)向分发队列提交任务

1.创建代码块

   提交到GCD中的代码块,是没有返回值的,他们都是dispatch_block_t类型的代码块,dispatch_queue_t 的定义如下:
   typedef void (^dispatch_block_t)( void)
       意味着加入 dispatch_queue 中的 block 必须是无参数也无返回值的。除了用代码块封装task外,我们也可以使用C语言函数来编写,然后将其提交到分发队列中,但是一般情况下建议使用代码块,这样可以充分利用代码块的“闭包”性质。
2.选择或者创建合适的分发队列  

   对于主队列和全局队列系统会默认创建,而且全局队列会有三个不同优先级(高、中、默认),向主线程中提交的代码块会在主线程中执行。

3.(同步、异步方式)提交任务

      可以用异步或同步的方式来提交一个代码块,具体选择什么样的方式可以根据情况而定。除此之外,也可以选择延迟方式提交。


二 队列的使用

1.主队列

      与UI相关的任务应该必须在主线程中来执行,使用dispatch_get_main_queue函数来取得主分发队列的句柄。可以以两种方式向主队列中来提交任务,这两种方式都是异步的,即不管该任务是否执行完毕,都不会阻塞下面任务的执行。

      dispatch_async   执行一个代码块
      dispatch_async_f 执行一个c函数(不常用)

注意:在主线程中不能以(当前提交任务所在的函数在主线程中)dispathch_sync同步的方式提交任务,因为如果此任务比较耗时的话,会阻塞后面的代码(主线程),导致无法响应用户的请求。所有在主线程中向主队列中提前的任务必须是异步的。

void dispatch_async(dispatch_queue_t queue,dispatch_block_t block);
 dispatch_async 有两个参数:
          1.分发队列的句柄   
          2.待执行的代码块,没有返回值和参数

a.
创建代码块
  void (^TaskOne)(void) = ^(void)
    {
       
 NSLog(@"Current thread = %@", [NSThread currentThread]);
       
 NSLog(@"Main thread = %@", [NSThread mainThread]);
       
        [[[
UIAlertView alloc] initWithTitle:@"GCD"
                                   
 message:@"Great Center Dispatcher"
                                  
 delegate:nil
                         
 cancelButtonTitle:@"OK"
                         
 otherButtonTitles:nil, nil] show];
    };

 b.
取得分发队列  
   
 dispatch_queue_t mainQueue = dispatch_get_main_queue();

 c.提交任务   
    dispatch_async(mainQueue, TaskOne);
  


 也可以一步完成:
   dispatch_async( dispatch_get_main_queue(), ^(void)
   {
       
        NSLog(@"Current thread = %@", [NSThread currentThread]);
       
 NSLog(@"Main thread = %@", [NSThread mainThread]);
      
        [[[
UIAlertView alloc] initWithTitle:@"GCD"
                                  
 message:@"Great Center Dispatcher"
                                 
 delegate:nil
                        
 cancelButtonTitle:@"OK"
                        
 otherButtonTitles:nil, nil] show];
    });


输出结果:

2013-11-08 15:09:27.268 GCDDemo[8567:70b] Current thread = <NSThread: 0x8a166c0>{name = (null), num = 1}
2013-11-08 15:09:27.270 GCDDemo[8567:70b] Main thread = <NSThread: 0x8a166c0>{name = (null), num = 1}

   上面定义的代码块的作用是用来打印当前的线程号和主线程号,通过输出发现他们都为1,说明代码块是在主线程中执行的。

2.全局队列

      下载并显示图片或大量的后台计算操作,可以使用GCD的全局同步队列。可以同步或异步的方式提交我们的任务。同步提交执行并不是意味着程序会阻塞一直到你的代码执行完毕,它只是意味着,同步队列会一直等待直达你的任务执行完毕,才开始执行队列中下一个代码块。

注意:
        a.当我们向全局队列提交一个任务后,程序不会阻塞,因为全局队列中的任务不是在主线程中执行的。但是有个例外,当一个任务以dispatch_sync的方式提交到全局或串行队列的话,IOS可能会在当前线程中(可能在主线程中)去执行,这取决于当前提交代码所在函数的环境。

上面是苹果官方文档的说明,下面例子会详细说明。
 
        b.如果我们以synchronously的方式分别向两个同步队列提交了两个任务,这两个任务是并行的,因为全局队列之间是并行的。

        c.如果我们有A,B两个任务,想当A执行完后B再执行的话,我们可以以同步方式向同一个队列中来提交我们的任务。


dispatch_queue_t dispatch_get_global_queue(
   long priority,
   unsigned long flags);

   第一个参数是优先级,优先级越高,获得的CPU的时间片也就越多,对列中的任务执行的也就越快。
   第二个参数暂时无意义,保留参数。

- (void) viewDidLoad
{
    void (^printFrom1To100)(void) = ^(void)
    {
       
 NSUInteger counter = 0;
       
 for (counter=1;counter<100;  counter++)
        {
           
 NSLog(@"Counter = %lu- Thread=%@",(unsigned long)counter,[NSThread currentThread]);
        }
     };
   
 dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
   
   
 dispatch_sync(concurrentQueue, printFrom1To100);
   
 dispatch_sync(concurrentQueue, printFrom1To100);
}

输出结果:
2013-11-08 15:33:01.252 GCDDemo[8649:70b] Counter = 1- Thread=<NSThread: 0x8a80280>{name = (null), num = 1}
2013-11-08 15:33:01.254 GCDDemo[8649:70b] Counter = 2- Thread=<NSThread: 0x8a80280>{name = (null), num = 1}
2013-11-08 15:33:01.255 GCDDemo[8649:70b] Counter = 3- Thread=<NSThread: 0x8a80280>{name = (null), num = 1}
2013-11-08 15:33:01.256 GCDDemo[8649:70b] Counter = 4- Thread=<NSThread: 0x8a80280>{name = (null), num = 1}
2013-11-08 15:33:01.257 GCDDemo[8649:70b] Counter = 5- Thread=<NSThread: 0x8a80280>{name = (null), num = 1}
2013-11-08 15:33:01.258 GCDDemo[8649:70b] Counter = 6- Thread=<NSThread: 0x8a80280>{name = (null), num = 1}
2013-11-08 15:33:01.259 GCDDemo[8649:70b] Counter = 7- Thread=<NSThread: 0x8a80280>{name = (null), num = 1}
2013-11-08 15:33:01.259 GCDDemo[8649:70b] Counter = 8- Thread=<NSThread: 0x8a80280>{name = (null), num = 1}
2013-11-08 15:33:01.260 GCDDemo[8649:70b] Counter = 9- Thread=<NSThread: 0x8a80280>{name = (null), num = 1}
2013-11-08 15:33:01.261 GCDDemo[8649:70b] Counter = 10- Thread=<NSThread: 0x8a80280>{name = (null), num = 1}
………...
2013-11-08 15:33:01.338 GCDDemo[8649:70b] Counter = 1- Thread=<NSThread: 0x8a80280>{name = (null), num = 1}
2013-11-08 15:33:01.339 GCDDemo[8649:70b] Counter = 2- Thread=<NSThread: 0x8a80280>{name = (null), num = 1}
2013-11-08 15:33:01.339 GCDDemo[8649:70b] Counter = 3- Thread=<NSThread: 0x8a80280>{name = (null), num = 1}
2013-11-08 15:33:01.340 GCDDemo[8649:70b] Counter = 4- Thread=<NSThread: 0x8a80280>{name = (null), num = 1}
2013-11-08 15:33:01.340 GCDDemo[8649:70b] Counter = 5- Thread=<NSThread: 0x8a80280>{name = (null), num = 1}
2013-11-08 15:33:01.341 GCDDemo[8649:70b] Counter = 6- Thread=<NSThread: 0x8a80280>{name = (null), num = 1}
2013-11-08 15:33:01.341 GCDDemo[8649:70b] Counter = 7- Thread=<NSThread: 0x8a80280>{name = (null), num = 1}
2013-11-08 15:33:01.342 GCDDemo[8649:70b] Counter = 8- Thread=<NSThread: 0x8a80280>{name = (null), num = 1}
2013-11-08 15:33:01.343 GCDDemo[8649:70b] Counter = 9- Thread=<NSThread: 0x8a80280>{name = (null), num = 1}
2013-11-08 15:33:01.344 GCDDemo[8649:70b] Counter = 10- Thread=<NSThread: 0x8a80280>{name = (null), num = 1}
………..

     上面我们定义了一个代码块,里面执行一个for循环,并打印当前和主线程的线程号。然后我们以同步的方式向全局队列提交了两次,观察结果我们发现:

a.Counter按照顺序1-100输出两遍,说明两个代码块是同步执行的,在前一个执行完后,后面一个才开始执行,也就是说第一个代码块的执行阻塞了全局队列(从而导致第二个代码块阻塞).
b.当前的线程号是1,说明该代码是在主线程中执行

     以上的结果印证了刚才所讲的,“当一个任务以dispatch_sync的方式提交到全局或串行队列的话,IOS可能会在当前线程中(可能在主线程中)去执行”,我们在- (void) viewDidLoad函数中提交的代码块,而这个函数是在主线程中执行的,我们的代码块也在主线程中执行。 
 
下面以异步的方式来提交任务:
- (void) viewDidLoad
{
    void (^printFrom1To100)(void) = ^(void)
    {
       
 NSUInteger counter = 0;
       
 for (counter=1;counter<100;  counter++)
        {
           
 NSLog(@"Counter = %lu- Thread=%@",(unsigned long)counter,[NSThread currentThread]);
        }
     };
   
 dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
   
   
 dispatch_async(concurrentQueue, printFrom1To100);
   
 dispatch_async(concurrentQueue, printFrom1To100);
}

输出结果:
2013-11-08 15:44:33.663 GCDDemo[8697:1303] Counter = 1- Thread=<NSThread: 0x8b0cdc0>{name = (null), num = 2}
2013-11-08 15:44:33.663 GCDDemo[8697:3207] Counter = 1- Thread=<NSThread: 0x8a39320>{name = (null), num = 3}
2013-11-08 15:44:33.666 GCDDemo[8697:1303] Counter = 2- Thread=<NSThread: 0x8b0cdc0>{name = (null), num = 2}
2013-11-08 15:44:33.666 GCDDemo[8697:3207] Counter = 2- Thread=<NSThread: 0x8a39320>{name = (null), num = 3}
2013-11-08 15:44:33.672 GCDDemo[8697:1303] Counter = 3- Thread=<NSThread: 0x8b0cdc0>{name = (null), num = 2}
2013-11-08 15:44:33.674 GCDDemo[8697:1303] Counter = 4- Thread=<NSThread: 0x8b0cdc0>{name = (null), num = 2}
2013-11-08 15:44:33.674 GCDDemo[8697:1303] Counter = 5- Thread=<NSThread: 0x8b0cdc0>{name = (null), num = 2}
2013-11-08 15:44:33.673 GCDDemo[8697:3207] Counter = 3- Thread=<NSThread: 0x8a39320>{name = (null), num = 3}
2013-11-08 15:44:33.674 GCDDemo[8697:1303] Counter = 6- Thread=<NSThread: 0x8b0cdc0>{name = (null), num = 2}
2013-11-08 15:44:33.674 GCDDemo[8697:3207] Counter = 4- Thread=<NSThread: 0x8a39320>{name = (null), num = 3}
2013-11-08 15:44:33.675 GCDDemo[8697:3207] Counter = 5- Thread=<NSThread: 0x8a39320>{name = (null), num = 3}
2013-11-08 15:44:33.677 GCDDemo[8697:3207] Counter = 6- Thread=<NSThread: 0x8a39320>{name = (null), num = 3}
2013-11-08 15:44:33.677 GCDDemo[8697:3207] Counter = 7- Thread=<NSThread: 0x8a39320>{name = (null), num = 3}
2013-11-08 15:44:33.678 GCDDemo[8697:3207] Counter = 8- Thread=<NSThread: 0x8a39320>{name = (null), num = 3}
2013-11-08 15:44:33.678 GCDDemo[8697:3207] Counter = 9- Thread=<NSThread: 0x8a39320>{name = (null), num = 3}


观察发现:
a.Counter中的数字交错输出,说明两个代码块异步方式并行运行
b.线程号分别为2和3.,说明两个代码块在不同的线程中执行(非主线程)。



     下面来看一个综合例子,下载一个图片 ,当图片下载完后在视图中显示图片,这种场景也是我们在项目中经常要用到的。


大概的代码实现框架如下:

    dispatch_queue_t concurrentQueue= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
   
 dispatch_async(concurrentQueue, ^(void)
    {
       
 __block UIImage *image = nil;
       
        dispatch_sync(concurrentQueue, ^(void)
        {
                  /* Download the image here */
        });

       
 dispatch_sync(dispatch_get_main_queue(), ^(void)
         {
               
 /* Show the image to the user here on the main queue*/
         }); 

     });


分析:
     我们以异步的方式来提交整个代码块,这样的话代码块的执行不会阻塞下面的代码。在代码块内我们又以同步的方式来执行了两个代码块,所以当执行“ Download the image here”代码块的时候它会阻塞后面的代码的执行,当下载完毕后,我们在主队列中同步的方式来显示图片(对所有涉及UI相关操作必须在主线程中去执行)。



三 自定义队列
  
直接看代码:

首先创建自己的串行队列:

  dispatch_queue_t firstSerialQueue = dispatch_queue_create("com.pixolity.GCD.serialQueue1", DISPATCH_QUEUE_SERIAL );

异步方式向队列中提交三个代码块:
    dispatch_async(firstSerialQueue, ^(
void)
    {
        NSUInteger counter =
 0;
       
 for (counter = 0;counter < 5;counter++)
        {
            NSLog(
@"First iteration, counter = %lu", (unsigned long)counter);
        }
    });
    dispatch_async(firstSerialQueue, ^(
void)
    {
        NSUInteger counter =
 0;
       
 for (counter = 0;counter < 5;counter++)
        {
            NSLog(
@"Second iteration, counter = %lu", (unsigned long)counter);
        }
    });
    dispatch_async(firstSerialQueue, ^(
void)
    {
        NSUInteger counter =
 0;
       
 for (counter = 0;counter < 5;counter++)
        {
            NSLog(
@"Third iteration, counter = %lu", (unsigned long)counter);
        }
    });

输出结果:

2013-11-08 17:16:27.721 GCDDemo[9081:2b03] First iteration, counter = 0  Thread=<NSThread: 0x8b91210>{name = (null), num = 2}
2013-11-08 17:16:27.724 GCDDemo[9081:2b03] First iteration, counter = 1  Thread=<NSThread: 0x8b91210>{name = (null), num = 2}
2013-11-08 17:16:27.724 GCDDemo[9081:2b03] First iteration, counter = 2  Thread=<NSThread: 0x8b91210>{name = (null), num = 2}
2013-11-08 17:16:27.725 GCDDemo[9081:2b03] First iteration, counter = 3  Thread=<NSThread: 0x8b91210>{name = (null), num = 2}
2013-11-08 17:16:27.725 GCDDemo[9081:2b03] First iteration, counter = 4  Thread=<NSThread: 0x8b91210>{name = (null), num = 2}
2013-11-08 17:16:27.726 GCDDemo[9081:2b03] Sencond iteration, counter = 0  Thread=<NSThread: 0x8b91210>{name = (null), num = 2}
2013-11-08 17:16:27.726 GCDDemo[9081:2b03] Sencond iteration, counter = 1  Thread=<NSThread: 0x8b91210>{name = (null), num = 2}
2013-11-08 17:16:27.727 GCDDemo[9081:2b03] Sencond iteration, counter = 2  Thread=<NSThread: 0x8b91210>{name = (null), num = 2}
2013-11-08 17:16:27.727 GCDDemo[9081:2b03] Sencond iteration, counter = 3  Thread=<NSThread: 0x8b91210>{name = (null), num = 2}
2013-11-08 17:16:27.727 GCDDemo[9081:2b03] Sencond iteration, counter = 4  Thread=<NSThread: 0x8b91210>{name = (null), num = 2}
2013-11-08 17:16:27.745 GCDDemo[9081:2b03] Third iteration, counter = 0  Thread=<NSThread: 0x8b91210>{name = (null), num = 2}
2013-11-08 17:16:27.745 GCDDemo[9081:2b03] Third iteration, counter = 1  Thread=<NSThread: 0x8b91210>{name = (null), num = 2}
2013-11-08 17:16:27.746 GCDDemo[9081:2b03] Third iteration, counter = 2  Thread=<NSThread: 0x8b91210>{name = (null), num = 2}
2013-11-08 17:16:27.747 GCDDemo[9081:2b03] Third iteration, counter = 3  Thread=<NSThread: 0x8b91210>{name = (null), num = 2}
2013-11-08 17:16:27.751 GCDDemo[9081:2b03] Third iteration, counter = 4  Thread=<NSThread: 0x8b91210>{name = (null), num = 2}


同步的方式提交代码块:
 dispatch_sync(firstSerialQueue, ^(void)
    {
        NSUInteger counter =
 0;
       
 for (counter = 0;counter < 5;counter++)
        {
            NSLog(
@"####:sync   counter = %lu  Thread=%@", (unsigned long)counter,[NSThread currentThread]);
        }
    });
2013-11-08 17:19:00.818 GCDDemo[9110:70b] ####:sync   counter = 0  Thread=<NSThread: 0x8a81110>{name = (null), num = 1}
2013-11-08 17:19:00.819 GCDDemo[9110:70b] ####:sync   counter = 1  Thread=<NSThread: 0x8a81110>{name = (null), num = 1}
2013-11-08 17:19:00.819 GCDDemo[9110:70b] ####:sync   counter = 2  Thread=<NSThread: 0x8a81110>{name = (null), num = 1}
2013-11-08 17:19:00.820 GCDDemo[9110:70b] ####:sync   counter = 3  Thread=<NSThread: 0x8a81110>{name = (null), num = 1}
2013-11-08 17:19:00.842 GCDDemo[9110:70b] ####:sync   counter = 4  Thread=<NSThread: 0x8a81110>{name = (null), num = 1}


然后创建自己的同步队列:

dispatch_queue_t firstSerialQueue = dispatch_queue_create("com.pixolity.GCD.serialQueue1", DISPATCH_QUEUE_CONCURRENT );
   
 dispatch_async(firstSerialQueue, ^(void)
    {
       
 NSUInteger counter = 0;
       
 for (counter = 0;counter < 5;counter++)
        {
           
 NSLog(@"First iteration, counter = %lu  Thread=%@", (unsigned long)counter,[NSThread currentThread]);
        }
    });
   
 dispatch_async(firstSerialQueue, ^(void)
    {
       
 NSUInteger counter = 0;
       
 for (counter = 0;counter < 5;counter++)
        {
            
 NSLog(@"Sencond iteration, counter = %lu  Thread=%@", (unsigned long)counter,[NSThread currentThread]);                    
        }
    });
   
 dispatch_async(firstSerialQueue, ^(void)
    {
       
 NSUInteger counter = 0;
       
 for (counter = 0;counter < 5;counter++)
        {
            
 NSLog(@"Third iteration, counter = %lu  Thread=%@", (unsigned long)counter,[NSThread currentThread]);
        }
    });
    
输出结果:
2013-11-11 16:52:00.429 GCDDemo[1302:3703] Sencond iteration, counter = 0  Thread=<NSThread: 0x8b93730>{name = (null), num = 3}
2013-11-11 16:52:00.429 GCDDemo[1302:3307] First iteration, counter = 0  Thread=<NSThread: 0x8a5ddf0>{name = (null), num = 2}
2013-11-11 16:52:00.433 GCDDemo[1302:3307] First iteration, counter = 1  Thread=<NSThread: 0x8a5ddf0>{name = (null), num = 2}
2013-11-11 16:52:00.433 GCDDemo[1302:3703] Sencond iteration, counter = 1  Thread=<NSThread: 0x8b93730>{name = (null), num = 3}
2013-11-11 16:52:00.434 GCDDemo[1302:3307] First iteration, counter = 2  Thread=<NSThread: 0x8a5ddf0>{name = (null), num = 2}
2013-11-11 16:52:00.435 GCDDemo[1302:3703] Sencond iteration, counter = 2  Thread=<NSThread: 0x8b93730>{name = (null), num = 3}
2013-11-11 16:52:00.436 GCDDemo[1302:3307] First iteration, counter = 3  Thread=<NSThread: 0x8a5ddf0>{name = (null), num = 2}
2013-11-11 16:52:00.436 GCDDemo[1302:3703] Sencond iteration, counter = 3  Thread=<NSThread: 0x8b93730>{name = (null), num = 3}
2013-11-11 16:52:00.437 GCDDemo[1302:3c03] Third iteration, counter = 0  Thread=<NSThread: 0x8a5a970>{name = (null), num = 4}
2013-11-11 16:52:00.438 GCDDemo[1302:3307] First iteration, counter = 4  Thread=<NSThread: 0x8a5ddf0>{name = (null), num = 2}
2013-11-11 16:52:00.439 GCDDemo[1302:3c03] Third iteration, counter = 1  Thread=<NSThread: 0x8a5a970>{name = (null), num = 4}
2013-11-11 16:52:00.439 GCDDemo[1302:3703] Sencond iteration, counter = 4  Thread=<NSThread: 0x8b93730>{name = (null), num = 3}
2013-11-11 16:52:00.440 GCDDemo[1302:3c03] Third iteration, counter = 2  Thread=<NSThread: 0x8a5a970>{name = (null), num = 4}
2013-11-11 16:52:00.441 GCDDemo[1302:3c03] Third iteration, counter = 3  Thread=<NSThread: 0x8a5a970>{name = (null), num = 4}
2013-11-11 16:52:00.441 GCDDemo[1302:3c03] Third iteration, counter = 4  Thread=<NSThread: 0x8a5a970>{name = (null), num = 4}

同步的方式提交代码块:
 dispatch_sync(firstSerialQueue, ^(void)
    {
        NSUInteger counter =
 0;
       
 for (counter = 0;counter < 5;counter++)
        {
            NSLog(
@"####:sync   counter = %lu  Thread=%@", (unsigned long)counter,[NSThread currentThread]);
        }
    });
2013-11-11 17:02:02.221 GCDDemo[1348:70b] ####:sync   counter = 0  Thread=<NSThread: 0x8a406c0>{name = (null), num = 1}
2013-11-11 17:02:02.221 GCDDemo[1348:70b] ####:sync   counter = 1  Thread=<NSThread: 0x8a406c0>{name = (null), num = 1}
2013-11-11 17:02:02.222 GCDDemo[1348:70b] ####:sync   counter = 2  Thread=<NSThread: 0x8a406c0>{name = (null), num = 1}
2013-11-11 17:02:02.222 GCDDemo[1348:70b] ####:sync   counter = 3  Thread=<NSThread: 0x8a406c0>{name = (null), num = 1}
2013-11-11 17:02:02.223 GCDDemo[1348:70b] ####:sync   counter = 4  Thread=<NSThread: 0x8a406c0>{name = (null), num = 1}

观察发现:
1.dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)
    第一个参数是一个c语言形式的字符串
    第二个参数在可以是  DISPATCH_QUEUE_SERIAL (orNULL) 来创建串行队列
                                        DISPATCH_QUEUE_CONCURRENT   来创建同步队列

2.自定义串行队列是严格按照提交FIFO的原则来执行任务,不管你是以何种方式来提交待任务。
3.以同步方式提交的任务都会在当前提交的线程中去执行。例如,在主线程中以同步方式提交的代码块,线程号是1(主线程)。
4.以异步方式提交的任务,它们都不会在当前线程中执行,对于串行队列来说它们都会在同一个线程中去执行,而对于同步队列来说它们分别在不同的线程中去执行。

5.串行队列是系统相关的,为了和别的程序串行队列不冲突,建议使用反转DNS来命名串行队列,以保证唯一性。

6. 自定义串行队列中的任务是串行执行的(不管以何种方式进行提交)。正因为如此,它们可以用来完成同步机制, 有点像传统线程中的mute。


四 延迟提交代码块

直接看代码:

 NSLog(@"here......");
 double delayInSeconds = 5.0;
 dispatch_time_t delayInNanoSeconds =  dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
 dispatch_after(delayInNanoSeconds, concurrentQueue, ^(void)
  {
        NSLog(
@"delay execute......");
  });

输出结果:
2013-11-08 17:07:00.215 GCDDemo[9036:70b] here......
2013-11-08 17:07:05.252 GCDDemo[9036:1303] delay execute......


观察结果:发现代码块块的执行时间比之前的代码晚了5秒钟void 

dispatch_after(dispatch_time_t when,dispatch_queue_t queue,dispatch_block_t block);

第一个参数用来指定延迟的事件,用dispatch_time函数来构建
第二个参数用来指定队列
第三个参数用来指定要运行的代码块


五  总结

   使用GCD主要把握好每种队列的特点,以及任务提交方式和实际运行线程的对应关系。
   向主队列不管以何种方式提交的代码块总会在主线程中运行,而且为了防止在主线程内提交代码块阻塞主线程,最好以异步的方式来提交代码块;以同步的方式向全局队列和自定义队列提交的代码块,会在当前提交所在线程内执行代码块,不会在另外的线程来执行,以异步的方式提交到全局队列的代码块和自定义队列中的代码块不会阻塞当前线程,会在另外线程中执行;不管以同步还是异步的方式向自定义串行队列提交代码块,都会严格按照提交顺序去执行(one by one);以异步方式向自定义同步队列,会为每个代码块创建一个线程,而以异步方式向自定义串行队列提交的代码块会在同一个线程中执行。
       
Immich vs Nextcloud照片管理实测:自建私有云相册到底选哪个? 本文深度评测了Immich与Nextcloud在私有云相册管理中的表现,涵盖核心功能、性能基准、本土化实践及进阶功能。Immich凭借微服务架构和AI优化在照片管理、移动端体验上表现优异,而Nextcloud则强在生态整合。文章还提供了Docker部署优化和国内网络适配方案,帮助用户根据需求选择最佳方案。 阅读详情

相关推荐

SurfaceControlViewHost使用介绍

可以看到,主要用途:是把一个进程的View显示到另外一个进程里面。

chadm.xiang 1285

ios 线程休眠_iOS多线程之超实用理论+demo演示(可下载)

目录背景简介GCD、OperationQueue 对比 核心理念区别GCD 队列 串行队列(Serial Queues)并发队列(Concurrent Queues)串行、并发队列对比图注意事项block(块)相关dispatch_afterdispatch_semaphoredispatch_apply自问自答OperationQueue 可以实现 非FIFO 效果队列暂停/...

weixin_39915210的博客 202

保姆级教程:用Wokwi玩转ESP32 MicroPython仿真(含库文件配置指南)

本教程详细介绍了如何使用Wokwi平台进行ESP32 MicroPython仿真开发,包括库文件配置、传感器数据模拟和REPL调试技巧。通过Wokwi的仿真调试系统,开发者可以在浏览器中快速验证代码逻辑,提高开发效率,特别适合物联网项目的快速迭代。

weixin_29195615的博客 446

【C++】gcd函数的写法

gcd函数 C++写gcd函数有几种写法,下面介绍几种。 while循环 inline int(int a,int b) { int r; while(b>0) { r=a%b; a=b; b=r; } return a; } 三目运算符 inline int gcd(int a,int b) { ...

Ljnoit 7万+

基于wxWidgets框架,使用DialogBlocks建立OpenGL界面

前言 之前公司要求使用wxWidgets做GUI,基于OpenGL图形内核,开发三维可视化工具。目前初步开发工作基本已经完成,剩下都是完善了。这里记录一下最开始的框架搭建过程(当然是简化版啦)。wxWidgets结合OpenGL开发可以实现跨平台应用,再结合CMake和VS Code,整体开发工具用习惯了会感觉非常顺手。 界面编辑 首先,使用DialogBlocks新建一个工程,这里工程目录...

cyberobot的博客 2750

PX4从放弃到精通(二十二):日志

文章目录前言一、下载日志二、ulog转CSV三、利用flightplot软件分析PX4的ulog日志1 windos安装2 ubuntu18.04安装四、使用PlotJuggler分析PX4日志五、设置日志记录条件六、添加自定义日志消息 前言 PX4 1.10以上固件 QGC 一、下载日志 将飞控链接地面站,在下图页面点击“刷新”,即可看到保存的日志(前提是要有TF卡) 选择需要下载的日志,点击右侧的“下载”,然后选择目录即可进行下载,如果想擦除所有的日志,可以点击右侧的“擦除全部” 二、ulog转CS

超维空间科技的博客 6796

gcd 算法实现 c/c++

废话不说,直接上代码 如有错误欢迎指正 #include using namespace std; void exchange( int& m, int& n ) { int t = m; m = n; n = t; return; } bool is_positive( int m ) { return m > 0 ; } int gc

ShiningStarPxx的专栏 7337

SDMA 如何实现设备对主机内存的访问

摘要:SDMA(System Direct Memory Access)是PCIe设备直接访问主机内存的核心机制,使外设无需CPU干预即可高效读写系统RAM。其实现原理包括:设备作为主控发起DMA请求,通过PCIe Memory TLP访问主机物理地址;完整通路涉及驱动分配DMA安全内存、设备配置、地址转换(IOMMU)和中断通知等步骤;关键技术涵盖地址类型(HPA/IOVA)、TLP格式、缓存一致性和安全防护机制。SDMA广泛应用于GPU、网卡、NVMe等高性能场景,是现代异构计算的基础技术,需软硬件协同

MHD0815的博客 240

iOS GCD学习《二》

GCD学习《一》 iOS GCD信号量的使用 Swift中队列的创建 public convenience init(label: String, qos: DispatchQoS = .unspecified, attributes: DispatchQueue.Attributes = [], autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency = .inherit, target: DispatchQueue? = nil) labe

我的专栏 805

BLDC控制实验:方波、霍尔、开环、定速、正转

本文记录博主学习BLDC控制软件的过程。 文章目录1 概述2 软件架构及工具链2.1 软件架构2.2 工具链3 底层代码生成3.1 时钟配置3.2 按键输入配置 1 概述 本文是博主第一次做BLDC控制实验,目的仅仅是写代码让BLDC转起来,而暂时不考虑其他复杂的需求。 控制的方法是比较简单的六步换相法。利用电机内部的霍尔传感器,通过参考电机厂家给出的二二导通换相表,生成方波来控制电机。第一次实验为了简化需求,只考虑开环、定速、正转的情况: 开环:不考虑速度反馈,直接给PWM让电机转起来; 定速:不考虑速

u013288925的博客 1万+

飞牛fnNAS搭建Web网页版OFFICE(WPS)软件

本文介绍了如何在飞牛NAS上通过Docker容器部署WPS Office办公软件。主要内容包括:启用Docker服务、准备项目文件夹结构、使用Compose方式构建容器、解决端口冲突问题、配置中文输入法和字体库,以及通过ZeroTier实现远程访问。文章详细说明了每个步骤的操作方法,包括容器启动、输入法设置、字体添加和文件存储位置配置。最后还介绍了使用ZeroTier内网穿透技术实现远程访问NAS上WPS服务的方法,让用户可以在不同设备上随时编辑NAS中的文件。整个部署过程完整清晰,为NAS用户提供了便捷的

dgnankai的专栏 1701

iOS之线程(二)GCD

概念 GCD:Gtand Central Dispatch 中枢调度器 GCD主要解决的是多核并行运算 GCD是自动管理线程的生命周期的 任务 要执行的操作 同步函数:在当前线程中执行任务,不具备开启新线程的能力 异步函数:可以在新的线程中执行任务,具备开启新线程的能力 队列 用来存放任务 并发队列(异步函数才有效) 串行队列 一般使用情况 声明一个任务 将任务添加到队列中 GC...

chase的博客 309

mjlab MuJoCo 人形机器人强化学习入门教程(一)安装配置使用

mjlab是融合IsaacLab API与MuJoCo物理引擎的强化学习工具,提供轻量级GPU加速仿真方案。当前处于测试阶段,支持Linux系统(推荐)和有限macOS支持。核心优势包括:1)直接集成MuJoCo Warp实现裸机性能;2)保留IsaacLab成熟的RL抽象层;3)简化安装流程。与IsaacLab相比更专注于MuJoCo生态,适合刚体机器人RL研究。文档包含详细安装指南、平台兼容性说明、与IsaacLab的API差异对比及常见问题解答。项目正在积极开发中,欢迎社区贡献和反馈。

2506_90492529的博客 1997

iOS GCD(二)

上篇记录了GCD的各种基本使用方法及特点,下面是GCD在项目中的常用场景 1、创建单例 dispatch_once static People *sharePeople = nil; + (instancetype)sharePeople{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{

小宇文 611

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

iOS开发之浅谈GCD的使用(二)

iOS开发之浅谈GCD的使用(二)系统提供的global队列上次说到系统给我们提供了四个队列, 分别是global队列的四种优先级. 我们打印四个优先级队列的地址, 可以看到四个优先级队列的地址是不同的, 所以这是四个不同的队列, 然后我们在同一个程序不同的地方去打印, 发现同优先级的队列的地址是相同的. 所以可以得出, 在一个程序中, 在任何地方调用dispatch_get_global_queu

qq247359468的专栏 387

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

【iOS开发-多线程【二】 GCD<二>】

GCD的实现和API一样重要,主要解释了如何将串行并行和同步异步任务结合达到提升进程的效果。

weixin_61639290的博客 539

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

iOS多线程开发—GCD(二)

前言 在上一篇文章iOS多线程开发—GCD(二)中我介绍了什么是多线程,GCD与线程的关系,以及如何创建队列和简单的使用,在这篇文章中我讲重点总结一下GCD一些高级用法。 创建dispatch_queue_t需要注意的问题 我们可以通过dispatch_get_global_queue(long identifier, unsigned long flags);获取全局队列,通过dispatch_...

weixin_33676492的博客 239

iOS 多线程开发之OperationQueue(二)NSOperation VS GCD

原创Blog,转载请注明出处 blog.youkuaiyun.com/hello_hwc欢迎关注我的iOS SDK详解专栏 http://blog.youkuaiyun.com/column/details/huangwenchen-ios-sdk.html前言:最近有点忙,所以这个月更新的博客数量有些下降,估计这个月和下个月博客更新的数量都在10篇左右。回到正题,本文会比较下GCD和NSOperation两种多线程的

Leo的专栏 3927

iOS GCD(二) dispatch_group 队列组

有时候我们会有这样的需求:分别异步执行2个耗时任务,然后当2个耗时任务都执行完毕后再回到主线程执行任务。这时候我们可以用到 GCD 的队列组。 使用场景: 同时上传多个图片,所有图片上传完成之后去请求服务器上传图片地址。 dispatch_group_notify 原理:使用函数dispatch_group_create创建dispatch group,然后使用函数dispatch_group_a...

春风酿酒的博客 1279

iOS--GCD(二)

上一篇中,我们可以了解到GCD关于串行、并行最基本的用法,接下来我们来了解下GCD其他方面的功能。 延迟执行 after double delayInSeconds = 3.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));

one1a1s的专栏 409

IOS - 总结下swift使用GCD 多线程(二)GCD和DispatchQueue

1.前言 iOS中处理多核并发的技术有两种分别是:`Grand Central Dispatch`(以下简称`GCD`)和`NSOperationQueue`框架。iOS开发的老司机们在程序开发中处理多个任务同时执行的时候,一定都会使用到这两个框架,而且GCD依靠它简洁的语法和对block的运用一直很受大家的青睐。ios开发中你一定明白 这样一条原则:“任何用于界面ui刷新和用户交互的...

weixin_30478757的博客 279

iOS 开始GCD的研究(二)

2017年3月18号续(一)。因为我发现一些东西,那就是学了新的东西,千万别忘记一件事情,那就是巩固知识。因为知识只要不巩固,不复习,基本很快就会忘记的,所以一定要过几天回来看。下面我就巩固一下昨天的知识,昨天的知识我发现有点乱糟糟的。今天又看了一下,文顶顶对GCD的理解。·GCD中有两个核心概念: 任务:执行什么操作 队列:用来存放任务 使用GCD的两个步骤: 制定任务 确定想要做的事 将任务添加

feilv520的专栏 285

【iOS多线程(二)】GCD其他方法详解

以一个停车场的运作为例。简单起见,假设停车场只有三个车位,一开始三个车位都是空的。这时如果同时来了五辆车,看 门人允许其中三辆直接进入,然后放下车拦,剩下的车则必须在入口等待,此后来的车也都不得不在入口处等待。这时,有一辆车离开停车场,看门人得知后,打开 车拦,放入外面的一辆进去,如果又离开两辆,则又可以放入两辆,如此往复。在这个停车场系统中,车位是公共资源,每辆车好比一个线程,看门人起的就是信号量的作用。我们使用GCD的时候如何让线程同步,也有多种方法。

cheng_lin0201的博客 1214

iOS进阶_GCD(二.GCD串行队列&并发队列)

GCD 核心概念:将任务添加到队列,指定任务执行的方法 任务 使用block封装 block 就是一个提前准备好的代码块,在需要的时候执行 队列(负责调度任务) 串行队列:一个接一个的调度任务 并发队列:可以同时调度多个任务 任务执行函数(任务都需要在线程中执行!) 同步执行:当前指令不完成,不会执行下个指令 异步执行:当前指令不完成,同样可以执行下一条指令 总结: -开不开线...

十二指环的博客 3185

iOS多线程(二)GCD

GCD 全称是Grand Central Dispatch,“伟大的中枢调度器”GCD是苹果公司为多核的并行运算提出的解决方案纯C语言,提供了非常多强大的函数 优势 GCD会自动利用更多的CPU内核(比如双核、四核)GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码 基本概念 任务和队

stubbornness1219的博客 792

iOS GCD集汇(二)GCD详解---->很详细噢

@原文地址:http://blog.youkuaiyun.com/springpp1990/article/details/12451913

iOS界@迷糊小书童 1995
上一篇: IOS GCD 使用(一) 简介
下一篇: IOS GCD 使用(三)单例模式
张哲BJUT
博客等级 码龄15年 151粉丝 111原创
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值