服务器之家:专注于服务器技术及软件下载分享
分类导航

服务器资讯|IT/互联网|云计算|区块链|软件资讯|操作系统|手机数码|百科知识|免费资源|头条新闻|

服务器之家 - 新闻资讯 - 操作系统 - 纤程与协程的区别

纤程与协程的区别

2023-11-17 17:03未知服务器之家 操作系统

纤程(Fiber)是 Windows 操作系统提供的概念。那什么是纤程呢? 纤程是一种比线程更轻量级的执行单元,它可以在一个线程中切换执行,不需要操作系统内核的干预。纤程可以用来实现异步任务,避免了创建新线程的开销。纤程也

纤程(Fiber)是 Windows 操作系统提供的概念。那什么是纤程呢?

纤程是一种比线程更轻量级的执行单元,它可以在一个线程中切换执行,不需要操作系统内核的干预。纤程可以用来实现异步任务,避免了创建新线程的开销。纤程也叫做协程(coroutine),是一种用户态的多任务机制。

纤程与协程的区别

协程与纤程主要的区别点:

  • 纤程是操作系统级别的实现,而协程是语言级别的实现。纤程被操作系统内核控制,协程对于内核而言不可见。
  • 纤程和线程类似,都拥有自己的栈、寄存器现场等资源,但是纤程更轻量级,一个线程可以包含多个纤程。协程也可以有自己的栈(stackful)或者共享栈(stackless),但是寄存器现场由用户代码保存和恢复。
  • 纤程之间的切换由用户控制,需要显式地调用转换函数。协程之间的切换也由用户控制,但是可以通过生成器、异步函数等语法糖来隐式地实现。
  • 纤程只出现在 Windows 上,而协程在很多语言和平台上都有支持。

一个简单的纤程程序,创建两个纤程并在它们之间切换:

#include "pch.h"
#include <iostream>
#include <windows.h>
#include <tchar.h>

#define FIBER_COUNT 2

LPVOID g_lpFiber[FIBER_COUNT] = {};

VOID WINAPI FiberFun(LPVOID pParam) //纤程函数的返回类型为VOID,并不是因为返回值没有意义,而是因为这个函数不应该返回!
{
    int nFiberIndex = (int)pParam;
    while (true)
    {
        std::cout << "Fiber" << nFiberIndex << std::endl;
        SwitchToFiber(g_lpFiber[1 - nFiberIndex]); //切换到另一个纤程
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    LPVOID lpMainFiber = ConvertThreadToFiber(NULL); //将当前线程转换为主纤程
    if (lpMainFiber == NULL)
    {
        std::cout << "ConvertThreadToFiber failed" << std::endl;
        return -1;
    }

    for (int i = 0; i < FIBER_COUNT; i++)
    {
        g_lpFiber[i] = CreateFiber(0, FiberFun, (LPVOID)i); //创建子纤程
        if (g_lpFiber[i] == NULL)
        {
            std::cout << "CreateFiber failed" << std::endl;
            return -1;
        }
    }

    SwitchToFiber(g_lpFiber[0]); //切换到第一个子纤程

    for (int i = 0; i < FIBER_COUNT; i++)
    {
        DeleteFiber(g_lpFiber[i]); //删除子纤程
    }

    ConvertFiberToThread(); //将主纤程转换回线程

    return 0;
}

一个使用纤程实现协同程序的例子:

#include <windows.h>
#include <stdio.h>

#define MAX_FIBERS 3

DWORD dwCounter;

void WINAPI MyFunc(LPVOID lpParameter)
{
 DWORD dwIndex;

 dwIndex = *(DWORD *)lpParameter;

 while(TRUE)
 {
  printf("dwCounter=%d,dwIndex=%d\n",dwCounter,dwIndex);
  dwCounter++;
  SwitchToFiber(lpParameter);
 }
}

void main()
{
 LPVOID lpMainAddress;
 LPVOID lpAddress[MAX_FIBERS];
 DWORD dwParameter[MAX_FIBERS];
 int i;

 lpMainAddress=ConvertThreadToFiber(NULL);

 for(i=0;i<MAX_FIBERS;i++)
 {
  dwParameter[i]=i+1;
  lpAddress[i]=CreateFiber(0,(LPFIBER_START_ROUTINE)MyFunc,&dwParameter[i]);
 }

 for(i=0;i<10;i++)
  SwitchToFibers(lpAddress[i%MAX_FIBERS]);

 for(i=0;i<MAX_FIBERS;i++)
  DeleteFibers(lpAddress[i]);

 printf("end\n");
}
  • 协程是一种在应用层模拟的线程,它可以在不同的执行点之间切换,而不需要操作系统的干预。
  • 协程可以提高程序的性能和并发能力,同时也简化了异步编程的复杂度。
  • 协程是一种轻量级的并发技术,它可以在单个线程内执行多个任务,从而实现高效的并发操作。与线程相比,协程的优势在于它可以避免线程切换的开销,减少资源占用,同时也更易于编程。

尽管协程的概念早于线程,但协程的实现并不是所有操作系统原生支持的。目前,很多编程语言都是通过自己的运行时环境来模拟协程,利用线程技术来实现协程的调度。这些语言中,像 golang 这样的语言在实现上比较成熟,可以支持大量的协程同时执行,这也是 golang 能够处理高并发的原因之一。

在 golang 中,协程的实现是基于线程的,它维护了一个协程队列,由多个线程来负责执行协程队列中的任务。当一个协程在执行过程中遇到了阻塞操作,比如等待 IO 数据返回,它会被放入一个阻塞队列中,等待 IO 数据返回后再继续执行。在这个过程中,当前线程会去执行队列中的其他协程,从而实现协程之间的切换。

延伸 · 阅读

精彩推荐