1.知道操作系统在线程等待IO的时候,会阻塞当前线程,切换到其它线程,这样在当前线程等待IO的过程中,其它线程可以继续执行。当系统线程较少的时候没有什么问题,但是当线程数量非常多的时候,却产生了问题。
**一是系统线程会占用非常多的内存空间,二是过多的线程切换会占用大量的系统时间。**
此时,协程的出现正好可以解决这两个问题。协程是运行在线程之上,当一个协程执行完成之后,可以选择主动让出,让另一个协程运行在当前的线程之上。协程并没有增加线程的数量,只是在线程的基础上通过**分时复用**的方式运行多个协程,
而且**协程的切换在用户态完成,切换的代价比线程从用户态到内核态的代价小很多。**
**但是,操作系统是不知道协程的存在,只知道线程,**协程只有在等待IO过程中才能重复利用线程,线程在等待IO的过程中会陷入阻塞状态。因此在协程调用阻塞IO操作的时候,操作系统会让线程进入阻塞状态,当前的协程和其它绑定在该线程之上的协程都会陷入阻塞而得不到调度,这往往是不能接受的。
**因此在协程中不能调用导致线程阻塞的操作。**也就是说,协程只有和异步IO结合起来,才能发挥最大的威力。
那么如何处理在协程中调用**阻塞IO**的操作呢?一般有2种处理方式:
1、在调用阻塞IO操作的时候,重新启动一个线程去执行这个操作,等执行完成后,协程再去读取结果。这其实和**多线程**没有太大区别。
2、对系统的IO进行封装,改成**异步调用**的方式,这需要大量的工作,最好寄希望于编程语言原生支持。
问:当协程需要IO操作时,将其挂起,且调用其他的协程。被挂起的协程进行IO操作?
答:是的,这种情况描述的是典型的异步IO模型。当一个协程需要执行IO操作时,它会被挂起(即暂停执行),而不会阻塞整个线程。然后,调度器可以选择执行其他处于就绪状态的协程,以确保线程的利用率。
被挂起的协程会发起IO操作,但是这个IO操作通常是异步的,意味着它会在后台进行,而不会阻塞线程。一旦IO操作完成,系统会通知相应的协程,并将其重新放入调度器以便继续执行。
这种方式下,线程可以在一个IO操作的等待期间继续执行其他协程,从而提高了并发性和效率。这种模型通常称为非阻塞IO模型,因为在执行IO操作时,线程不会被阻塞。
问:所以协程出现的原因是将线程的运行步骤分解为有IO和没有IO的部分,有IO的部分运行时被挂起,没有IO的部分就像线程一样被调度运行?
答:协程的出现正是为了解决传统线程模型中存在的一些问题,其中一个主要问题就是阻塞IO操作会导致线程被阻塞,从而影响了整个线程的执行效率。通过将线程的执行步骤分解为有IO和没有IO的部分,并且允许在有IO的部分执行时挂起,协程实现了非阻塞IO的效果,从而更好地利用了线程资源。
在协程中,当执行到IO操作时,协程会暂时挂起,而调度器可以选择执行其他处于就绪状态的协程,这样就不会因为某个协程的IO操作而阻塞整个线程。只有当IO操作完成后,被挂起的协程才会被重新调度执行。这种方式使得程序能够更加高效地利用线程,并且在IO密集型任务中表现得更加出色。