Multithread, single-threaded, synchronous, asynchronous, concurrent and parallel, serial queues and parallel queues. See here.

Keywords: iOS network

Multithread development took a long time, but has not been in-depth understanding. There has been some confusion for a long time. Only after a thorough understanding, did we find that there were many mistakes in our previous understanding.

Single thread equals synchronization and multi-thread equals asynchrony

  • This understanding is intuitive, after all, how asynchronous is only one thread?

Node.js is not convinced. I am single-threaded and I can be asynchronous. On Asynchronism and Single Thread in Node.
After reading this article, I understand that single thread can also be asynchronous, IO and other time-consuming operations like boiling water, I can cut vegetables at this time, this is asynchronous ah.
Wait a minute. It seems a little wrong. Who's going to open io and who's going to inform the cpu that I'm over?
Implementation of Node.js Asynchronous IO This article solves my doubts.

  • In Node.js, only the code written by oneself runs on the main thread, but the internal is not single-threaded. The bottom layer written by C opens the thread to do IO operation.

It suddenly dawned on me that there would be a working thread pool waiting for cpu access. Similar to IO, when a network requests such time-consuming operations, threads will be placed in a pool of threads that need to wait (blocking), and will not gain access to the cpu until the operation is completed.

With this understanding, concurrency and parallelism are easy.

  • The time for each thread to gain access to the cpu is a time slice. When it runs out, it has to wait for the next time. Time slice is very short, people simply do not realize that the feeling is parallel, but in fact it is only "pseudo parallel", that is, concurrent.

Now that the concepts are all over, let's talk about iOS multithreading. In fact, the theory is the same, no more than the acquisition of threads, open, end and so on. But iOS is different. He has GCD. That's a magic weapon.
There has always been a misconception about the serial queue and parallel queue of GCD:

Queue is thread, async is another thread, sync is blocking thread

Practice is the only way to know, to really understand, async, sync, serial queue, parallel queue, the main queue, or to personally test it.

  • Whether to open a new thread under the main thread
//Main queue
dispatch_async(dispatch_get_main_queue(), ^{
    NSLog(@"%@",[NSThread currentThread]);
});
    
dispatch_sync(dispatch_get_main_queue(), ^{
    NSLog(@"%@",[NSThread currentThread]);
});

//Serial queue
dispatch_queue_t ser_queue = dispatch_queue_create("serial", 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]);
});

//Parallel queue
dispatch_queue_t con_queue = dispatch_queue_create("parallel", 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]);
});
  • Is asynchrony a new thread under non-main threads

    dispatch_queue_t ser_queue = dispatch_queue_create("serial", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t con_queue = dispatch_queue_create("parallel", 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]);
        });
    });
  • Synchronization is a new thread under non-main threads

    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]);
        });
    });

Conclusion:
The result is not posted, or better to test it yourself. It's a pleasure to see if your ideas and answers are the same.
It basically covers all the possibilities. It feels more like queue-oriented. Threads are scheduled by the system itself.

The sensation is to answer two questions:

  • When will async start new threads
  • When sync causes deadlock

My answer:

  • Main queue: must be in the main thread
  • Serial queue: async opens a thread
  • Parallel queues: async has multiple threads
  • Deadlock: It must be a serial queue, followed by the queue in which the block is submitted and the queue in which the block is put.
  • Different queues of async are basically on different threads. (doubtful)
  • The queue submitting the block is the same as the queue put in by the block, regardless of serial parallelism, on the same thread. (doubtful)

GCD is an artifact. There are many things to learn. I recommend some classic articles.
GCD literacyTalk about GCD
GCD advanced articles
Deadlock, graphics and text, clear and easy to understand

Posted by seeya on Wed, 17 Apr 2019 16:15:33 -0700