为您推荐:
精华内容
最热下载
问答
  • 3KB weixin_42133918 2021-05-30 22:24:12
  • 36KB weixin_38744778 2021-05-31 04:05:51
  • 193KB weixin_38611459 2021-03-01 20:47:04
  • 3KB weixin_42132056 2021-06-07 17:48:54
  • 207B xy_z_H 2021-01-13 12:46:03
  • 2.29MB jokers201 2018-03-27 17:28:01
  • 37KB weiboyuan 2018-05-08 16:03:42
  • 78KB weixin_38742954 2021-01-04 05:29:40
  • 356KB qq_30758221 2018-07-19 19:53:45
  • 80KB weixin_38685882 2021-01-03 16:16:00
  • 84KB weixin_42107561 2021-08-05 03:05:12
  • 817KB weixin_38743968 2019-09-15 05:58:44
  • 14.46MB south_000 2020-03-06 09:57:12
  • 294KB weixin_38713039 2020-09-01 07:15:45
  • 2KB weixin_38720322 2021-05-30 05:16:13
  • 229KB weixin_38720009 2021-01-03 20:16:29
  • 41KB weixin_38614391 2020-08-24 23:01:09
  • ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b); } 二进制算法 在1e4以内的运算次数中,gcd的递归比较快,但是当运算次数高达1e6及以上,位运算算法非常节省时间 实现原理: 若a、b都是偶数,则gcd(a,b...

    辗转相除法(欧几里得算法)

    时间复杂度 O ( l o g n ) O(logn) O(logn)

    //不必在意a、b大小关系,即使a小于b,第一次递归也会交换a和b
    typedef long long ll;
    ll gcd(ll a,ll b){
    	return b==0?a:gcd(b,a%b);
    }
    
    

    二进制算法

    在1e4以内的运算次数中,gcd的递归比较快,但是当运算次数高达 1 e 6 1e^6 1e6及以上,位运算算法非常节省时间

    实现原理:

    a , b a,b a,b都是偶数,则 g c d ( a , b ) = 2 ∗ g c d ( a / 2 , b / 2 ) gcd(a,b)=2*gcd(a/2,b/2) gcd(a,b)=2gcd(a/2,b/2)

    a , b a,b a,b都是奇数,则有 g c d ( a , b ) = g c d ( a − b , b ) gcd(a,b)=gcd(a-b,b) gcd(a,b)=gcd(ab,b)

    a a a为偶数, b b b为奇数,则有 g c d ( a , b ) = g c d ( a / 2 , b ) gcd(a,b)=gcd(a/2,b) gcd(a,b)=gcd(a/2,b)

    int gcd(int a,int b){
    	int c=1;
    	while(a-b){
    		if(a&1){
    			if(b&1){
    				if(a>b)a=(a-b)>>1;
    				else b=(b-a)>>1;
    			}else b>>=1;
    		}else{
    			if(b&1)a>>=1;else c<<=1,a>>=1,b>>=1;
    		}
    	}
    	return c*a;
    }
    

    递推求gcd

    n , m n,m n,m以内任意两数的 g c d , l c m gcd,lcm gcd,lcm,时间复杂度 O ( n m ) O(nm) O(nm)

    类似埃氏筛法,因为前面的数互质,他们两两之间最大公因数都是确定为 1 1 1的,如"1 1",“1 2”,“2 3”,“3 4”。从小到大枚举 k k k,这样 k i ki ki k j kj kj的最大公因数就是k,同理最小公倍数就是 ( k i ∗ k j ) / k = i ∗ j ∗ k (ki*kj)/k=i*j*k (kikj)/k=ijk

    int gcd[maxn][maxn],lcm[maxn][maxn];
    
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) if(!gcd[i][j])
            for(int k=1;k*i<=n && k*j<=m;k++)
                gcd[k*i][k*j]=k,lcm[k*i][k*j]=i*j*k;
    

    GCD常见推导

    • g c d ( a , b ) = c − − − − − > g c d ( a / c , b / c ) = 1 gcd(a,b)=c -----> gcd(a/c,b/c)=1 gcd(a,b)=c>gcd(a/c,b/c)=1
    • l c m ( a , b ) = a ∗ b / g c d ( a , b ) = c − − − − − − > c ∗ g c d ( a , b ) = a ∗ b − − − − − − > g c d ( a , b ) = a ∗ b / c lcm(a,b)=a*b/gcd(a,b)=c ------> c*gcd(a,b)=a*b ------> gcd(a,b)=a*b/c lcm(a,b)=ab/gcd(a,b)=c>cgcd(a,b)=ab>gcd(a,b)=ab/c
    • g c d ( a , b , c ) = g c d ( g c d ( a , b ) , c ) gcd(a,b,c)=gcd(gcd(a,b),c) gcd(a,b,c)=gcd(gcd(a,b),c) g c d gcd gcd具有区间可加性,当我们对一个区间求 g c d gcd gcd时可以先求出所有的任何小区间的 g c d gcd gcd再逐层求出大区间的 g c d gcd gcd,可以考虑线段树或者 d p dp dp

    GCD常见应用

    如下图 n × m n×m n×m的方格棋盘,从左下角到右上角穿过一条直线,求直线和多少个方格内部有交点
    在这里插入图片描述
    观察每一个点,不难发现每当和一条纵线相交后,下一次一定个横线相交,不考虑特殊点的情况下是 n + m n+m n+m。但是像图中加粗的点那样,就重复计算了一次,因此需要找出这种特殊点的个数。从左下角开始找第一个特殊点,其左下角为 2 × 3 2×3 2×3的矩形;然后找第二个特殊点,左下角为 4 × 6 4×6 4×6的矩形;第三个为 6 × 9 6×9 6×9的矩形…我们发现一个共同点,就是这些矩形都和 n × m n×m n×m的矩形相似,所以特殊点的个数也就是 g c d ( n , m ) gcd(n,m) gcd(n,m),故答案就是 n + m − g c d ( n , m ) n+m-gcd(n,m) n+mgcd(n,m)

    2.有一个 n × n n×n n×n的方阵,给出方阵中的两个坐标 ( x 1 , y 1 ) , ( x 2 , y 2 ) (x_1,y_1),(x_2,y_2) (x1,y1),(x2,y2),如何判断两点的连线不会和其他点相交
    在这里插入图片描述
    如图所示,显然如果两个点之间会有交点,那么 △ A B C △ABC ABC △ A E F △AEF AEF会构成相似三角形,和第一个例子类似,那么就出现 g c d ( ∣ B C ∣ , ∣ A C ∣ ) > 1 gcd(|BC|,|AC|)>1 gcd(BC,AC)>1

    因此令 a = a b s ( x 1 − x 2 ) , b = a b s ( y 1 − y 2 ) a=abs(x_1-x_2),b=abs(y_1-y_2) a=abs(x1x2),b=abs(y1y2),当且仅当 g c d ( a , b ) = 1 gcd(a,b)=1 gcd(a,b)=1时两点的连线才不会和其他点相交

    GCD和LCM在质因数分解下的意义

    假设 a a a经过质因数分解后为 P 1 k 1 ∗ P 2 k 2 , . . . ∗ P n k n P_1^{k_1}*P_2^{k_2},...*P_n^{k_n} P1k1P2k2,...Pnkn,b经过质因数分解为 Q 1 t 1 ∗ Q 2 t 2 , . . . ∗ Q m t m Q_1{t_1}*Q_2^{t_2},...*Q_m^{t_m} Q1t1Q2t2,...Qmtm

    假设质因子 p p p a a a b b b共有的质因子,在 a a a p p p的幂次为 k 1 k_1 k1,在 b b b p p p的幂次为 k 2 k_2 k2,又因为所有的质因子两两互质,互不影响

    那么 g c d ( a , b ) gcd(a,b) gcd(a,b)的质因子 p p p实际上的幂次为 m i n ( k 1 , k 2 ) min( k_1,k_2 ) min(k1,k2) l c m ( a , b ) lcm(a,b) lcm(a,b)的质因子 p p p实际上的幂次为 m a x ( k 1 , k 2 ) max( k_1,k_2 ) max(k1,k2)

    展开全文
    qq_44691917 2020-01-27 17:57:22
  • 291KB weixin_38685832 2020-09-01 06:27:31
  • 64KB weixin_39803108 2018-12-14 11:38:53
  • 1KB weixin_38747917 2021-05-30 20:52:44
  • 989.2MB henry_lei 2020-12-01 16:43:10
  • gcd( int a, int b) { if (b== 0 ) return a; return gcd(b,a %b ); } int main() { int m ,n; while (~scanf( " %d %d " ,& m ,&n)) { printf ( " %d \n" ,gcd( m ,n)); } return 0 ; }

    我的心愿是世界和平!

    递归实现辗转相除法。

    #include<stdio.h>
    int gcd(int a,int b)
    {
        if(b==0)
            return a;
        return gcd(b,a%b);
    }
    int main()
    {
        int m,n;
        while(~scanf("%d%d",&m,&n))
        {
            printf("%d\n",gcd(m,n));
        }
        return 0;
    }
    展开全文
    yuancijian 2017-07-28 10:25:13
  • 原文链接:... GCD 简介2. GCD 任务和队列3. GCD 的使用步骤4. GCD 的基本使用(6种不同组合区别)1. GCD 简介什么是 GCD 呢?我们先来看看百度百科的解释简单了解下概念Grand Central Dispa...

    原文链接:https://www.jianshu.com/p/2d57c72016c6

    本文用来介绍 iOS 多线程中 GCD 的相关知识以及使用方法。通过本文,您将了解到:

    1. GCD 简介

    2. GCD 任务和队列

    3. GCD 的使用步骤

    4. GCD 的基本使用(6种不同组合区别)

    1. GCD 简介

    什么是 GCD 呢?我们先来看看百度百科的解释简单了解下概念Grand Central Dispatch(GCD)是 Apple 开发的一个多核编程的较新的解决方法。它主要用于优化应用程序以支持多核处理器以及其他对称多处理系统。它是一个在线程池模式的基础上执行的并发任务。在 Mac OS X 10.6 雪豹中首次推出,也可在 iOS 4 及以上版本使用。

    为什么要用 GCD 呢?

    因为 GCD 有很多好处啊,具体如下:GCD 可用于多核的并行运算

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

    GCD 会自动管理线程的生命周期(创建线程、调度任务、销毁线程)

    程序员只需要告诉 GCD 想要执行什么任务,不需要编写任何线程管理代码

    既然 GCD 有这么多的好处,那么下面我们就来系统的学习一下 GCD 的使用方法。

    2. GCD 任务和队列

    学习 GCD 之前,先来了解 GCD 中两个核心概念:任务和队列。

    任务:就是执行操作的意思,换句话说就是你在线程中执行的那段代码。在 GCD 中是放在 block 中的。执行任务有两种方式:同步执行(sync)和异步执行(async)。两者的主要区别是:是否等待队列的任务执行结束,以及是否具备开启新线程的能力。

    同步执行(sync):

    同步添加任务到指定的队列中,在添加的任务执行结束之前,会一直等待,直到队列里面的任务完成之后再继续执行。

    只能在当前线程中执行任务,不具备开启新线程的能力。

    异步执行(async):

    异步添加任务到指定的队列中,它不会做任何等待,可以继续执行任务。

    可以在新的线程中执行任务,具备开启新线程的能力。

    举个简单例子:你要打电话给小明和小白。

    同步执行就是,你打电话给小明的时候,不能同时打给小白,等到给小明打完了,才能打给小白(等待任务执行结束)。而且只能用当前的电话(不具备开启新线程的能力)。

    而异步执行就是,你打电话给小明的时候,不等和小明通话结束,还能直接给小白打电话,不用等着和小明通话结束再打(不用等待任务执行结束)。除了当前电话,你还可以使用其他所能使用的电话(具备开启新线程的能力)。

    注意:异步执行(async)虽然具有开启新线程的能力,但是并不一定开启新线程。这跟任务所指定的队列类型有关(下面会讲)。

    队列(Dispatch Queue):这里的队列指执行任务的等待队列,即用来存放任务的队列。队列是一种特殊的线性表,采用 FIFO(先进先出)的原则,即新任务总是被插入到队列的末尾,而读取任务的时候总是从队列的头部开始读取。每读取一个任务,则从队列中释放一个任务。队列的结构可参考下图:

    12e856dce5b9

    Serial串行队列.png

    在 GCD 中有两种队列:串行队列和并发队列。两者都符合 FIFO(先进先出)的原则。两者的主要区别是:执行顺序不同,以及开启线程数不同。

    串行队列(Serial Dispatch Queue):

    每次只有一个任务被执行。让任务一个接着一个地执行。(只开启一个线程,一个任务执行完毕后,再执行下一个任务)

    并发队列(Concurrent Dispatch Queue):

    可以让多个任务并发(同时)执行。(可以开启多个线程,并且同时执行任务)注意:并发队列的并发功能只有在异步(dispatch_async)函数下才有效

    两者具体区别如下两图所示。

    12e856dce5b9

    串行队列.png

    12e856dce5b9

    并发队列.png

    3. GCD 的使用步骤

    GCD 的使用步骤其实很简单,只有两步。

    1.创建一个队列(串行队列或并发队列)

    2.将任务追加到任务的等待队列中,然后系统就会根据任务类型执行任务(同步执行或异步执行)

    下边来看看队列的创建方法/获取方法,以及任务的创建方法。

    3.1 队列的创建方法/获取方法

    可以使用dispatch_queue_create来创建队列,需要传入两个参数,第一个参数表示队列的唯一标识符,用于 DEBUG,可为空,Dispatch Queue 的名称推荐使用应用程序 ID 这种逆序全程域名;第二个参数用来识别是串行队列还是并发队列。DISPATCH_QUEUE_SERIAL表示串行队列,DISPATCH_QUEUE_CONCURRENT表示并发队列。// 串行队列的创建方法dispatch_queue_tqueue= dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_SERIAL);

    // 并发队列的创建方法dispatch_queue_tqueue= dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_CONCURRENT);

    对于串行队列,GCD 提供了的一种特殊的串行队列:主队列(Main Dispatch Queue)。

    a.所有放在主队列中的任务,都会放到主线程中执行。

    b.可使用dispatch_get_main_queue()获得主队列。// 主队列的获取方法

    dispatch_queue_t queue= dispatch_get_main_queue();

    对于并发队列,GCD 默认提供了全局并发队列(Global Dispatch Queue)。

    a.可以使用dispatch_get_global_queue来获取。需要传入两个参数。第一个参数表示队列优先级,一般用DISPATCH_QUEUE_PRIORITY_DEFAULT。第二个参数暂时没用,用0即可。// 全局并发队列的获取方法

    dispatch_queue_tqueue= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

    3.2 任务的创建方法

    GCD 提供了同步执行任务的创建方法dispatch_sync和异步执行任务创建方法dispatch_async。// 同步执行任务创建方法

    dispatch_sync(queue, ^{// 这里放同步执行任务代码});

    // 异步执行任务创建方法

    dispatch_async(queue, ^{// 这里放异步执行任务代码});

    虽然使用 GCD 只需两步,但是既然我们有两种队列(串行队列/并发队列),两种任务执行方式(同步执行/异步执行),那么我们就有了四种不同的组合方式。这四种不同的组合方式是:同步执行 + 并发队列

    异步执行 + 并发队列

    同步执行 + 串行队列

    异步执行 + 串行队列

    实际上,刚才还说了两种特殊队列:全局并发队列、主队列。全局并发队列可以作为普通并发队列来使用。但是主队列因为有点特殊,所以我们就又多了两种组合方式。这样就有六种不同的组合方式了。同步执行 + 主队列

    异步执行 + 主队列

    那么这几种不同组合方式各有什么区别呢,这里为了方便,先上结果,再来讲解。你可以直接查看表格结果,然后跳过4. GCD的基本使用。

    12e856dce5b9

    下边我们来分别讲讲这几种不同的组合方式的使用方法。

    4. GCD 的基本使用

    先来讲讲并发队列的两种执行方式。

    4.1 同步执行 + 并发队列

    在当前线程中执行任务,不会开启新线程,执行完一个任务,再执行下一个任务。/**

    * 同步执行 + 并发队列

    * 特点:在当前线程中执行任务,不会开启新线程,执行完一个任务,再执行下一个任务。

    */

    - (void)syncConcurrent {

    NSLog(@"currentThread---%@",[NSThreadcurrentThread]);

    // 打印当前线程NSLog(@"syncConcurrent---begin");

    dispatch_queue_tqueue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_CONCURRENT);

    dispatch_sync(queue, ^{

    // 追加任务1

    for(inti =0; i <2; ++i) {

    [NSThreadsleepForTimeInterval:2];// 模拟耗时操作

    NSLog(@"1---%@",[NSThreadcurrentThread]);// 打印当前线程

    }

    });

    dispatch_sync(queue, ^{

    // 追加任务2

    for(inti =0; i <2; ++i) {

    [NSThreadsleepForTimeInterval:2];// 模拟耗时操作

    NSLog(@"2---%@",[NSThreadcurrentThread]);// 打印当前线程

    }

    });

    dispatch_sync(queue, ^{

    // 追加任务3

    for(inti =0; i <2; ++i) {

    [NSThreadsleepForTimeInterval:2];// 模拟耗时操作

    NSLog(@"3---%@",[NSThreadcurrentThread]);// 打印当前线程

    }

    });

    NSLog(@"syncConcurrent---end");}输出结果:

    2018-02-23 20:34:55.095932+0800 YSC-GCD-demo[19892:4996930] currentThread---{number = 1, name = main}

    2018-02-23 20:34:55.096086+0800 YSC-GCD-demo[19892:4996930] syncConcurrent---begin

    2018-02-23 20:34:57.097589+0800 YSC-GCD-demo[19892:4996930] 1---{number = 1, name = main}

    2018-02-23 20:34:59.099100+0800 YSC-GCD-demo[19892:4996930] 1---{number = 1, name = main}

    2018-02-23 20:35:01.099843+0800 YSC-GCD-demo[19892:4996930] 2---{number = 1, name = main}

    2018-02-23 20:35:03.101171+0800 YSC-GCD-demo[19892:4996930] 2---{number = 1, name = main}

    2018-02-23 20:35:05.101750+0800 YSC-GCD-demo[19892:4996930] 3---{number = 1, name = main}

    2018-02-23 20:35:07.102414+0800 YSC-GCD-demo[19892:4996930] 3---{number = 1, name = main}

    2018-02-23 20:35:07.102575+0800 YSC-GCD-demo[19892:4996930] syncConcurrent---end

    从同步执行 + 并发队列中可看到:

    a.所有任务都是在当前线程(主线程)中执行的,没有开启新的线程(同步执行不具备开启新线程的能力)。

    b.所有任务都在打印的syncConcurrent---begin和syncConcurrent---end之间执行的(同步任务需要等待队列的任务执行结束)。

    任务按顺序执行的。按顺序执行的原因:虽然并发队列可以开启多个线程,并且同时执行多个任务。但是因为本身不能创建新线程,只有当前线程这一个线程(同步任务不具备开启新线程的能力),所以也就不存在并发。而且当前线程只有等待当前队列中正在执行的任务执行完毕之后,才能继续接着执行下面的操作(同步任务需要等待队列的任务执行结束)。所以任务只能一个接一个按顺序执行,不能同时被执行。

    4.2 异步执行 + 并发队列

    可以开启多个线程,任务交替(同时)执行。/**

    * 异步执行 + 并发队列

    * 特点:可以开启多个线程,任务交替(同时)执行。

    */- (void)asyncConcurrent {

    NSLog(@"currentThread---%@",[NSThreadcurrentThread]);

    // 打印当前线程NSLog(@"asyncConcurrent---begin");

    dispatch_queue_tqueue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(queue, ^{

    // 追加任务1for(inti =0; i <2; ++i) {

    [NSThreadsleepForTimeInterval:2];// 模拟耗时操作

    NSLog(@"1---%@",[NSThreadcurrentThread]);// 打印当前线程}

    });

    dispatch_async(queue, ^{

    // 追加任务2

    for(inti =0; i <2; ++i) {

    [NSThreadsleepForTimeInterval:2];// 模拟耗时操作

    NSLog(@"2---%@",[NSThreadcurrentThread]);// 打印当前线程

    }

    });

    dispatch_async(queue, ^{

    // 追加任务3

    for(inti =0; i <2; ++i) {

    [NSThreadsleepForTimeInterval:2];// 模拟耗时操作

    NSLog(@"3---%@",[NSThreadcurrentThread]);// 打印当前线程

    }

    });

    NSLog(@"asyncConcurrent---end");}输出结果:

    2018-02-23 20:36:41.769269+0800 YSC-GCD-demo[19929:5005237] currentThread---{number = 1, name = main}

    2018-02-23 20:36:41.769496+0800 YSC-GCD-demo[19929:5005237] asyncConcurrent---begin

    2018-02-23 20:36:41.769725+0800 YSC-GCD-demo[19929:5005237] asyncConcurrent---end

    2018-02-23 20:36:43.774442+0800 YSC-GCD-demo[19929:5005566] 2---{number = 5, name = (null)}

    2018-02-23 20:36:43.774440+0800 YSC-GCD-demo[19929:5005567] 3---{number = 4, name = (null)}

    2018-02-23 20:36:43.774440+0800 YSC-GCD-demo[19929:5005565] 1---{number = 3, name = (null)}

    2018-02-23 20:36:45.779286+0800 YSC-GCD-demo[19929:5005567] 3---{number = 4, name = (null)}

    2018-02-23 20:36:45.779302+0800 YSC-GCD-demo[19929:5005565] 1---{number = 3, name = (null)}

    2018-02-23 20:36:45.779286+0800 YSC-GCD-demo[19929:5005566] 2---{number = 5, name = (null)}

    在异步执行 + 并发队列中可以看出:

    a.除了当前线程(主线程),系统又开启了3个线程,并且任务是交替/同时执行的。(异步执行具备开启新线程的能力。且并发队列可开启多个线程,同时执行多个任务)。

    b.所有任务是在打印的syncConcurrent---begin和syncConcurrent---end之后才执行的。说明当前线程没有等待,而是直接开启了新线程,在新线程中执行任务(异步执行不做等待,可以继续执行任务)。

    接下来再来讲讲串行队列的两种执行方式。

    4.3 同步执行 + 串行队列

    不会开启新线程,在当前线程执行任务。任务是串行的,执行完一个任务,再执行下一个任务。/**

    * 同步执行 + 串行队列

    * 特点:不会开启新线程,在当前线程执行任务。任务是串行的,执行完一个任务,再执行下一个任务。

    */

    - (void)syncSerial {

    NSLog(@"currentThread---%@",[NSThreadcurrentThread]);// 打印当前线程

    NSLog(@"syncSerial---begin");

    dispatch_queue_tqueue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_SERIAL);

    dispatch_sync(queue, ^{

    // 追加任务1

    for(inti =0; i <2; ++i) {

    [NSThreadsleepForTimeInterval:2];// 模拟耗时操作

    NSLog(@"1---%@",[NSThreadcurrentThread]);// 打印当前线程

    }

    });

    dispatch_sync(queue, ^{

    // 追加任务2

    for(inti =0; i <2; ++i) {

    [NSThreadsleepForTimeInterval:2];// 模拟耗时操作

    NSLog(@"2---%@",[NSThreadcurrentThread]);// 打印当前线程

    }

    });

    dispatch_sync(queue, ^{

    // 追加任务3

    for(inti =0; i <2; ++i) {

    [NSThreadsleepForTimeInterval:2];// 模拟耗时操作

    NSLog(@"3---%@",[NSThreadcurrentThread]);// 打印当前线程

    }

    });

    NSLog(@"syncSerial---end");}输出结果为:

    2018-02-23 20:39:37.876811+0800 YSC-GCD-demo[19975:5017162] currentThread---{number = 1, name = main}

    2018-02-23 20:39:37.876998+0800 YSC-GCD-demo[19975:5017162] syncSerial---begin

    2018-02-23 20:39:39.878316+0800 YSC-GCD-demo[19975:5017162] 1---{number = 1, name = main}

    2018-02-23 20:39:41.879829+0800 YSC-GCD-demo[19975:5017162] 1---{number = 1, name = main}

    2018-02-23 20:39:43.880660+0800 YSC-GCD-demo[19975:5017162] 2---{number = 1, name = main}

    2018-02-23 20:39:45.881265+0800 YSC-GCD-demo[19975:5017162] 2---{number = 1, name = main}

    2018-02-23 20:39:47.882257+0800 YSC-GCD-demo[19975:5017162] 3---{number = 1, name = main}

    2018-02-23 20:39:49.883008+0800 YSC-GCD-demo[19975:5017162] 3---{number = 1, name = main}

    2018-02-23 20:39:49.883253+0800 YSC-GCD-demo[19975:5017162] syncSerial---end

    在同步执行 + 串行队列可以看到:

    a.所有任务都是在当前线程(主线程)中执行的,并没有开启新的线程(同步执行不具备开启新线程的能力)。

    b.所有任务都在打印的syncConcurrent---begin和syncConcurrent---end之间执行(同步任务需要等待队列的任务执行结束)。

    c.任务是按顺序执行的(串行队列每次只有一个任务被执行,任务一个接一个按顺序执行)。

    4.4 异步执行 + 串行队列

    会开启新线程,但是因为任务是串行的,执行完一个任务,再执行下一个任务/**

    * 异步执行 + 串行队列

    * 特点:会开启新线程,但是因为任务是串行的,执行完一个任务,再执行下一个任务。

    */

    - (void)asyncSerial {

    NSLog(@"currentThread---%@",[NSThreadcurrentThread]);// 打印当前线程

    NSLog(@"asyncSerial---begin");

    dispatch_queue_tqueue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_SERIAL);

    dispatch_async(queue, ^{

    // 追加任务1

    for(inti =0; i <2; ++i) {

    [NSThreadsleepForTimeInterval:2];// 模拟耗时操作

    NSLog(@"1---%@",[NSThreadcurrentThread]);// 打印当前线程

    }

    });

    dispatch_async(queue, ^{

    // 追加任务2

    for(int i =0; i <2; ++i) {

    [NSThreadsleepForTimeInterval:2];// 模拟耗时操作

    NSLog(@"2---%@",[NSThreadcurrentThread]);// 打印当前线程

    }

    });

    dispatch_async(queue, ^{

    // 追加任务3

    for(int i =0; i <2; ++i) {

    [NSThreadsleepForTimeInterval:2];// 模拟耗时操作

    NSLog(@"3---%@",[NSThreadcurrentThread]);// 打印当前线程

    }

    });

    NSLog(@"asyncSerial---end");}输出结果为:

    2018-02-23 20:41:17.029999+0800 YSC-GCD-demo[20008:5024757] currentThread---{number = 1, name = main}

    2018-02-23 20:41:17.030212+0800 YSC-GCD-demo[20008:5024757] asyncSerial---begin

    2018-02-23 20:41:17.030364+0800 YSC-GCD-demo[20008:5024757] asyncSerial---end

    2018-02-23 20:41:19.035379+0800 YSC-GCD-demo[20008:5024950] 1---{number = 3, name = (null)}

    2018-02-23 20:41:21.037140+0800 YSC-GCD-demo[20008:5024950] 1---{number = 3, name = (null)}

    2018-02-23 20:41:23.042220+0800 YSC-GCD-demo[20008:5024950] 2---{number = 3, name = (null)}

    2018-02-23 20:41:25.042971+0800 YSC-GCD-demo[20008:5024950] 2---{number = 3, name = (null)}

    2018-02-23 20:41:27.047690+0800 YSC-GCD-demo[20008:5024950] 3---{number = 3, name = (null)}

    2018-02-23 20:41:29.052327+0800 YSC-GCD-demo[20008:5024950] 3---{number = 3, name = (null)}

    在异步执行 + 串行队列可以看到:

    a.开启了一条新线程(异步执行具备开启新线程的能力,串行队列只开启一个线程)。

    b.所有任务是在打印的syncConcurrent---begin和syncConcurrent---end之后才开始执行的(异步执行不会做任何等待,可以继续执行任务)。

    c.任务是按顺序执行的(串行队列每次只有一个任务被执行,任务一个接一个按顺序执行)。

    下边讲讲刚才我们提到过的特殊队列:主队列。

    主队列:GCD自带的一种特殊的串行队列

    所有放在主队列中的任务,都会放到主线程中执行

    可使用dispatch_get_main_queue()获得主队列

    我们再来看看主队列的两种组合方式。

    4.5 同步执行 + 主队列

    同步执行 + 主队列在不同线程中调用结果也是不一样,在主线程中调用会出现死锁,而在其他线程中则不会。

    4.5.1 在主线程中调用同步执行 + 主队列

    互相等待卡住不可行/**

    * 同步执行 + 主队列

    * 特点(主线程调用):互等卡主不执行。

    * 特点(其他线程调用):不会开启新线程,执行完一个任务,再执行下一个任务。

    */

    - (void)syncMain {

    NSLog(@"currentThread---%@",[NSThreadcurrentThread]);

    // 打印当前线程

    NSLog(@"syncMain---begin");

    dispatch_queue_tqueue = dispatch_get_main_queue();

    dispatch_sync(queue, ^{

    // 追加任务1

    for(inti =0; i <2; ++i) {

    [NSThreadsleepForTimeInterval:2];// 模拟耗时操作

    NSLog(@"1---%@",[NSThreadcurrentThread]);// 打印当前线程

    }

    });

    dispatch_sync(queue, ^{

    // 追加任务2

    for(inti =0; i <2; ++i) {

    [NSThreadsleepForTimeInterval:2];// 模拟耗时操作

    NSLog(@"2---%@",[NSThreadcurrentThread]);// 打印当前线程

    }

    });

    dispatch_sync(queue, ^{

    // 追加任务3

    for(inti =0; i <2; ++i) {

    [NSThreadsleepForTimeInterval:2];// 模拟耗时操作

    NSLog(@"3---%@",[NSThreadcurrentThread]);// 打印当前线程

    }

    });

    NSLog(@"syncMain---end");}输出结果

    2018-02-23 20:42:36.842892+0800 YSC-GCD-demo[20041:5030982] currentThread---{number = 1, name = main}

    2018-02-23 20:42:36.843050+0800 YSC-GCD-demo[20041:5030982] syncMain---begin

    (lldb)

    在同步执行 + 主队列可以惊奇的发现:

    在主线程中使用同步执行 + 主队列,追加到主线程的任务1、任务2、任务3都不再执行了,而且syncMain---end也没有打印,在XCode 9上还会报崩溃。这是为什么呢?

    这是因为我们在主线程中执行syncMain方法,相当于把syncMain任务放到了主线程的队列中。而同步执行会等待当前队列中的任务执行完毕,才会接着执行。那么当我们把任务1追加到主队列中,任务1就在等待主线程处理完syncMain任务。而syncMain任务需要等待任务1执行完毕,才能接着执行。

    那么,现在的情况就是syncMain任务和任务1都在等对方执行完毕。这样大家互相等待,所以就卡住了,所以我们的任务执行不了,而且syncMain---end也没有打印。

    要是如果不在主线程中调用,而在其他线程中调用会如何呢?

    4.5.2 在其他线程中调用同步执行 + 主队列

    不会开启新线程,执行完一个任务,再执行下一个任务// 使用 NSThread 的 detachNewThreadSelector 方法会创建线程,并自动启动线程执行selector 任务[NSThread detachNewThreadSelector:@selector(syncMain) toTarget:selfwithObject:nil];输出结果:

    2018-02-23 20:44:19.377321+0800 YSC-GCD-demo[20083:5040347] currentThread---{number = 3, name = (null)}

    2018-02-23 20:44:19.377494+0800 YSC-GCD-demo[20083:5040347] syncMain---begin

    2018-02-23 20:44:21.384716+0800 YSC-GCD-demo[20083:5040132] 1---{number = 1, name = main}

    2018-02-23 20:44:23.386091+0800 YSC-GCD-demo[20083:5040132] 1---{number = 1, name = main}

    2018-02-23 20:44:25.387687+0800 YSC-GCD-demo[20083:5040132] 2---{number = 1, name = main}

    2018-02-23 20:44:27.388648+0800 YSC-GCD-demo[20083:5040132] 2---{number = 1, name = main}

    2018-02-23 20:44:29.390459+0800 YSC-GCD-demo[20083:5040132] 3---{number = 1, name = main}

    2018-02-23 20:44:31.391965+0800 YSC-GCD-demo[20083:5040132] 3---{number = 1, name = main}

    2018-02-23 20:44:31.392513+0800 YSC-GCD-demo[20083:5040347] syncMain---end

    在其他线程中使用同步执行 + 主队列可看到:

    a.所有任务都是在主线程(非当前线程)中执行的,没有开启新的线程(所有放在主队列中的任务,都会放到主线程中执行)。

    b.所有任务都在打印的syncConcurrent---begin和syncConcurrent---end之间执行(同步任务需要等待队列的任务执行结束)。

    c.任务是按顺序执行的(主队列是串行队列,每次只有一个任务被执行,任务一个接一个按顺序执行)。

    为什么现在就不会卡住了呢?

    因为syncMain 任务放到了其他线程里,而任务1、任务2、任务3都在追加到主队列中,这三个任务都会在主线程中执行。syncMain任务在其他线程中执行到追加任务1到主队列中,因为主队列现在没有正在执行的任务,所以,会直接执行主队列的任务1,等任务1执行完毕,再接着执行任务2、任务3。所以这里不会卡住线程。

    4.6 异步执行 + 主队列

    只在主线程中执行任务,执行完一个任务,再执行下一个任务。/**

    * 异步执行 + 主队列

    * 特点:只在主线程中执行任务,执行完一个任务,再执行下一个任务

    */

    - (void)asyncMain {

    NSLog(@"currentThread---%@",[NSThreadcurrentThread]);// 打印当前线程

    NSLog(@"asyncMain---begin");

    dispatch_queue_t queue = dispatch_get_main_queue();

    dispatch_async(queue, ^{

    // 追加任务1

    for(int i =0; i <2; ++i) {

    [NSThread sleepForTimeInterval:2];// 模拟耗时操作

    NSLog(@"1---%@",[NSThread currentThread]);// 打印当前线程

    }

    });

    dispatch_async(queue, ^{

    // 追加任务2

    for(int i =0; i <2; ++i) {

    [NSThread sleepForTimeInterval:2];// 模拟耗时操作

    NSLog(@"2---%@",[NSThread currentThread]);// 打印当前线程

    }

    });

    dispatch_async(queue, ^{

    // 追加任务3

    for(int i =0; i <2; ++i) {

    [NSThread sleepForTimeInterval:2];// 模拟耗时操作

    NSLog(@"3---%@",[NSThread currentThread]);// 打印当前线程

    }

    });

    NSLog(@"asyncMain---end");}输出结果:

    2018-02-23 20:45:49.981505+0800 YSC-GCD-demo[20111:5046708] currentThread---{number = 1, name = main}

    2018-02-23 20:45:49.981935+0800 YSC-GCD-demo[20111:5046708] asyncMain---begin

    2018-02-23 20:45:49.982352+0800 YSC-GCD-demo[20111:5046708] asyncMain---end

    2018-02-23 20:45:51.991096+0800 YSC-GCD-demo[20111:5046708] 1---{number = 1, name = main}

    2018-02-23 20:45:53.991959+0800 YSC-GCD-demo[20111:5046708] 1---{number = 1, name = main}

    2018-02-23 20:45:55.992937+0800 YSC-GCD-demo[20111:5046708] 2---{number = 1, name = main}

    2018-02-23 20:45:57.993649+0800 YSC-GCD-demo[20111:5046708] 2---{number = 1, name = main}

    2018-02-23 20:45:59.994928+0800 YSC-GCD-demo[20111:5046708] 3---{number = 1, name = main}

    2018-02-23 20:46:01.995589+0800 YSC-GCD-demo[20111:5046708] 3---{number = 1, name = main}

    在异步执行 + 主队列可以看到:

    a.所有任务都是在当前线程(主线程)中执行的,并没有开启新的线程(虽然异步执行具备开启线程的能力,但因为是主队列,所以所有任务都在主线程中)。

    b.所有任务是在打印的syncConcurrent---begin和syncConcurrent---end之后才开始执行的(异步执行不会做任何等待,可以继续执行任务)。

    c.任务是按顺序执行的(因为主队列是串行队列,每次只有一个任务被执行,任务一个接一个按顺序执行)。

    弄懂了难理解、绕来绕去的队列+任务之后,我们来学习一个简单的东西:5. GCD 线程间的通信。

    展开全文
    weixin_28365523 2021-05-26 02:03:52
  • 48KB weixin_39841856 2019-08-15 03:21:37
  • 464KB SSnTi 2020-02-09 13:33:58
  • 290KB qq_33314190 2019-03-19 16:24:27
  • 1.33MB xiaoerbuo 2018-02-06 08:54:33
  • 4KB chenzhao931885867 2018-11-15 14:35:10

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 174,951
精华内容 69,980
关键字:

gcd

友情链接: 强化学习David课件.rar