首页 > 其他分享 >Winsock I/O 模型:性能和可扩展性的关键

Winsock I/O 模型:性能和可扩展性的关键

时间:2024-05-24 22:29:48浏览次数:27  
标签:socket 可扩展性 模型 sock 应用程序 Winsock Select SOCKET

目录

引言

Select模型

简介

主要特点

优点

缺点

工作原理

示例用法

WSAAsyncSelect异步I/O模型

简介

工作原理

主要步骤

优点

缺点

示例代码

WSAEventSelect事件选择模型

简介

工作原理

主要步骤

优点

缺点

示例代码

重叠I/O模型

简介

工作原理

主要优势

应用场景

示例代码

完成端口模型

简介

工作原理

主要步骤

线程池

应用场景

示例代码

结论


引言


        在网络编程领域,输入/输出(I/O)模型是数据传输的基础架构。在Windows系统中,Winsock(Windows Sockets API)提供了多种I/O模型以支持不同的网络通信需求。

        本文将详细介绍Winsock提供的五种主要I/O模型:select模型、WSAAsyncSelect异步I/O模型、WSAEventSelect事件选择模型、重叠I/O模型和完成端口模型。

Select模型

简介

        Select模型是Windows Socket中最基本的一种同步I/O模型。它通过使用Select函数,开发者可以监视一组socket的状态变化,例如可读性、可写性、错误状态等。Select模型使用轮询机制,让开发者在一个线程内管理多个socket,有效减少资源的负担。然而,由于Select模型的低效轮询机制,在处理大规模并发连接时会面临性能瓶颈。

主要特点
  • **简单易用:**Select模型的API简单易用,易于理解和使用。
  • **多socket管理:**Select模型可以同时监视多个socket,并等待其中任何一个变为可读、可写或发生异常。
  • **跨平台支持:**Select模型在大多数操作系统上都得到了广泛的支持,包括Windows、Linux和macOS。
优点
  • **易于使用:**Select模型的简单API和直接的方法使其成为开发人员的理想选择。
  • **资源效率:**通过在单个线程内管理多个socket,Select模型最大限度地减少了资源消耗和开销。
  • **跨平台兼容性:**Select模型在不同平台上的广泛支持确保了其在各种环境中的适用性。
缺点
  • **轮询效率低下:**Select模型的轮询机制,即顺序检查每个socket的状态,会导致性能下降,尤其是在处理大量socket时。
  • **并发限制:**Select模型的单线程特性可能会限制并发性,从而阻碍对高水平并发I/O操作要求苛刻的应用程序的性能。
  • **可扩展性问题:**随着连接和I/O操作数量的增加,Select模型的轮询机制可能会不堪重负,导致可扩展性问题。
工作原理

        Select模型通过使用称为“fd_set”的数据结构来存储要监视的socket描述符来工作。fd_set结构包含三个集合:

  • **readfds:**包含可读socket描述符。
  • **writefds:**包含可写socket描述符。
  • **exceptfds:**包含遇到错误的socket描述符。

        开发人员可以将感兴趣的socket描述符添加到相应的fd_set中。然后,他们调用Select函数,并将fd_set作为参数传递。Select函数将阻塞,直到至少一个socket变为可读、可写或遇到错误。返回后,Select函数会更新fd_set结构,指示哪些socket已过渡到准备状态。然后,开发人员可以检查修改后的fd_set来处理相应的I/O操作。

示例用法

以下代码片段演示了使用Select模型监视两个socket的基本用法:

#include <winsock.h>

int main() {
    // 初始化Winsock
    WSADATA wsaData;
    int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed: %d\n", iResult);
        return 1;
    }

    // 创建socket
    SOCKET sock1 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock1 == INVALID_SOCKET) {
        printf("socket failed: %d\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }

    SOCKET sock2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock2 == INVALID_SOCKET) {
        printf("socket failed: %d\n", WSAGetLastError());
        closesocket(sock1);
        WSACleanup();
        return 1;
    }

    // 绑定socket
    sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(8080);
    serverAddr.sin_addr.s_addr = INADDR_ANY;

    int iBindResult1 = bind(sock1, (SOCKADDR*)&serverAddr, sizeof(serverAddr));
    if (iBindResult1 == SOCKET_ERROR) {
        printf("bind failed: %d\n", WSAGetLastError());
        closesocket(sock1);
        closesocket(sock2);
        WSACleanup();
        return 1;
    }

    int iBindResult2 = bind(sock2, (SOCKADDR*)&serverAddr, sizeof(serverAddr));
    if (iBindResult2 == SOCKET_ERROR) {
        printf("bind failed: %

WSAAsyncSelect异步I/O模型

简介

        WSAAsyncSelect 异步 I/O 模型提供了一种异步的方式来通知应用程序 socket 的状态变化。与 Select 模型的轮询机制不同,WSAAsyncSelect 使用消息队列来传递通知,使应用程序无需主动查询 socket 的状态即可获知其变化。

工作原理

        WSAAsyncSelect 模型的核心是将 socket 与一个消息队列关联起来。当 socket 的状态发生变化时,例如有数据可读或可写,系统就会向该消息队列发送一条消息。应用程序可以通过处理消息队列中的消息来响应相应的 I/O 操作。

主要步骤
  1. **创建消息队列:**应用程序首先需要创建一个消息队列,用于接收来自系统的通知消息。
  2. **关联 socket 和消息队列:**使用 WSAAsyncSelect 函数将 socket 与消息队列关联起来。
  3. **设置事件:**应用程序可以设置 WSAAsyncSelect 函数的参数,指定要通知的事件类型,例如可读、可写或错误。
  4. **处理消息:**应用程序需要有一个消息处理循环来不断地从消息队列中获取消息。
  5. **关闭 socket:**当应用程序不再需要使用 socket 时,需要使用 closesocket 函数关闭 socket 并取消其与消息队列的关联。
优点
  • **异步通知:**应用程序无需主动查询 socket 的状态,可以提高应用程序的响应速度和效率。
  • **减少资源占用:**应用程序无需使用轮询机制来监视 socket 状态,可以减少 CPU 资源的占用。
  • **易于实现:**WSAAsyncSelect 模型的 API 相对简单,易于理解和实现。
缺点
  • **消息队列延迟:**由于依赖消息队列传递通知,可能会存在消息处理的延迟。
  • **可扩展性问题:**在高并发情况下,消息队列可能会成为性能瓶颈。
示例代码

以下代码演示了如何使用 WSAAsyncSelect 模型来监视一个 socket:

#include <winsock.h>

int main() {
    // 初始化 Winsock
    WSADATA wsaData;
    int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed: %d\n", iResult);
        return 1;
    }

    // 创建 socket
    SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock == INVALID_SOCKET) {
        printf("socket failed: %d\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }

    // 创建消息队列
    MSGQUEUE hMsgQueue = CreateMsgQueue(NULL, 0, 0);
    if (hMsgQueue == NULL) {
        printf("CreateMsgQueue failed: %d\n", GetLastError());
        closesocket(sock);
        WSACleanup();
        return 1;
    }

    // 关联 socket 和消息队列
    WSAAsyncSelect(sock, hMsgQueue, WM_SOCKET_NOTIFY);

    // 设置事件
    WSAEventSelect(sock, FD_READ);

    // 消息处理循环
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        switch (msg.message) {
            case WM_SOCKET_NOTIFY: {
                WPARAM wParam = msg.wParam;
                LPARAM lParam = msg.lParam;

                // 处理 socket 事件
                switch (wParam) {
                    case FD_READ:
                        // 处理可读事件
                        break;
                    case FD_WRITE:
                        // 处理可写事件
                        break;
                    case FD_CLOSE:
                        // 处理连接关闭事件
                        break;
                    case FD_ERROR:
                        // 处理错误事件
                        break;
                }
                break;
            }
            default:
                DefWindowProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
        }
    }

    // 关闭 socket
    closesocket(sock);

    // 关闭消息队列
    CloseMsgQueue(hMsgQueue);

    // 清理 Winsock
    WSACleanup();

    return 0;
}

WSAEventSelect事件选择模型

简介

        WSAEventSelect 模型是 Winsock 提供的另一种事件驱动的异步 I/O 方式。与 WSAAsyncSelect 模型不同,WSAEventSelect 模型使用事件对象来表示 socket 的状态变化,而不是使用消息队列。这种模型允许开发者为每个 socket 创建一个事件对象,并将 socket 的状态变化与这些事件关联。随后,开发者可以使用 WaitForMultipleObjects 等函数来等待任何一个事件的触发。这种模型使得事件管理更加简洁,并且可以提供出色的性能表现。

工作原理

        WSAEventSelect 模型的核心是将 socket 与一个或多个事件对象关联起来。当 socket 的状态发生变化时,例如有数据可读或可写,系统就会将该事件的状态设置为已触发。应用程序可以使用 WaitForMultipleObjects 等函数来等待任何一个事件的触发。当一个事件被触发时,应用程序可以根据该事件的类型来执行相应的 I/O 操作。

主要步骤
  1. **创建事件对象:**应用程序首先需要为每个 socket 创建一个事件对象。
  2. **关联 socket 和事件对象:**使用 WSAEventSelect 函数将 socket 与事件对象关联起来。
  3. **设置事件:**应用程序可以设置 WSAEventSelect 函数的参数,指定要通知的事件类型,例如可读、可写或错误。
  4. **等待事件:**应用程序可以使用 WaitForMultipleObjects 等函数来等待任何一个事件的触发。
  5. **处理事件:**当一个事件被触发时,应用程序可以使用 GetEventObjectIdentity 函数来确定哪个 socket 的状态发生了变化,然后根据该事件的类型来执行相应的 I/O 操作。
  6. **关闭 socket:**当应用程序不再需要使用 socket 时,需要使用 closesocket 函数关闭 socket 并取消其与事件对象的关联。
优点
  • **简洁的事件管理:**WSAEventSelect 模型使用事件对象来表示 socket 的状态变化,使得事件管理更加简洁。
  • **出色的性能表现:**WSAEventSelect 模型可以提供出色的性能表现,因为它避免了消息队列的开销。
  • **易于扩展:**WSAEventSelect 模型易于扩展,因为它允许为每个 socket 创建多个事件对象。
缺点
  • **编程复杂度略高:**与 Select 模型相比,WSAEventSelect 模型的编程复杂度略高,因为它需要创建和管理事件对象。
  • **需要额外的内存分配:**事件对象的创建需要额外的内存分配。
示例代码

以下代码演示了如何使用 WSAEventSelect 模型来监视一个 socket:

#include <winsock.h>

int main() {
    // 初始化 Winsock
    WSADATA wsaData;
    int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed: %d\n", iResult);
        return 1;
    }

    // 创建 socket
    SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock == INVALID_SOCKET) {
        printf("socket failed: %d\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }

    // 创建事件对象
    WSAEVENT hEvent = WSAEventCreate(NULL, TRUE, TRUE, NULL);
    if (hEvent == NULL) {
        printf("WSAEventCreate failed: %d\n", GetLastError());
        closesocket(sock);
        WSACleanup();
        return 1;
    }

    // 关联 socket 和事件对象
    WSAEventSelect(sock, hEvent, FD_READ | FD_WRITE);

    // 等待事件
    DWORD dwWaitResult = WaitForMultipleObjects(1, &hEvent, TRUE, INFINITE);
    if (dwWaitResult == WAIT_FAILED) {
        printf("WaitForMultipleObjects failed: %d\n", GetLastError());
        WSACloseEvent(hEvent);
        closesocket(sock);
        WSACleanup();
        return 1;
    }

    // 处理事件
    WSAEVENT hTriggeredEvent = NULL;
    DWORD dwEventCount = 0;
    BOOL bSuccess = WSAEnumEvents(sock, NULL, &hTriggeredEvent, 1, &dwEventCount);
    if (bSuccess && dwEventCount > 0) {
        DWORD dwEventFlags;
        bSuccess = WSAEventGetInfo(hTriggeredEvent, 0, NULL, &dwEventFlags);

重叠I/O模型

简介

        重叠 I/O 模型是 Windows 独有的一种先进的异步 I/O 技术。它允许 I/O 操作在后台执行,应用程序无需等待 I/O 操作完成即可继续处理其他任务。与传统的阻塞 I/O 模型相比,重叠 I/O 模型可以显著提高应用程序的性能,尤其是在处理大量 I/O 操作的网络应用程序中。

工作原理

        重叠 I/O 模型的核心是使用 OVERLAPPED 结构体来管理 I/O 操作。OVERLAPPED 结构体包含以下成员:

  • hEvent:用于通知应用程序 I/O 操作完成的事件句柄。
  • Internal:保留供系统内部使用。
  • Offset:用于指示 I/O 操作要从文件或缓冲区的哪个位置开始。
  • InternalHigh:保留供系统内部使用。
  • Union:包含指向用于 I/O 操作的缓冲区的指针。

        应用程序可以使用 WSARecvWSASend 等函数来发起重叠 I/O 操作。这些函数会将 I/O 操作的参数和 OVERLAPPED 结构体作为参数传递。系统会将 I/O 操作排队并将其置于后台执行。当 I/O 操作完成时,系统会将 hEvent 事件设置为已触发状态,并通知应用程序。

主要优势
  • **提高性能:**重叠 I/O 模型可以显著提高应用程序的性能,因为应用程序无需等待 I/O 操作完成即可继续处理其他任务。
  • **提高响应速度:**重叠 I/O 模型可以提高应用程序的响应速度,因为应用程序可以同时处理多个 I/O 操作。
  • **降低资源占用:**重叠 I/O 模型可以降低应用程序对 CPU 资源的占用,因为 I/O 操作是在后台执行的。
应用场景

        重叠 I/O 模型适用于需要处理大量 I/O 操作的应用程序,例如:

  • **网络应用程序:**Web 服务器、客户端-服务器应用程序、P2P 应用程序等。
  • **文件 I/O 密集型应用程序:**数据库应用程序、视频编辑软件、大型文件传输应用程序等。
示例代码

以下代码演示了如何使用重叠 I/O 模型从套接字中接收数据:

#include <winsock.h>

int main() {
    // 初始化 Winsock
    WSADATA wsaData;
    int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed: %d\n", iResult);
        return 1;
    }

    // 创建套接字
    SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock == INVALID_SOCKET) {
        printf("socket failed: %d\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }

    // 绑定套接字
    sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(8080);
    serverAddr.sin_addr.s_addr = INADDR_ANY;

    int iBindResult = bind(sock, (SOCKADDR*)&serverAddr, sizeof(serverAddr));
    if (iBindResult == SOCKET_ERROR) {
        printf("bind failed: %d\n", WSAGetLastError());
        closesocket(sock);
        WSACleanup();
        return 1;
    }

    // 监听套接字
    int iListenResult = listen(sock, 5);
    if (iListenResult == SOCKET_ERROR) {
        printf("listen failed: %d\n", WSAGetLastError());
        closesocket(sock);
        WSACleanup();
        return 1;
    }

    // 接受连接
    sockaddr_in clientAddr;
    int clientAddrLen = sizeof(clientAddr);
    SOCKET clientSock = accept(sock, (SOCKADDR*)&clientAddr, &clientAddrLen);
    if (clientSock == INVALID_SOCKET) {
        printf("accept failed: %d\n", WSAGetLastError());
        closesocket(sock);
        WSACleanup();
        return 1;
    }

    // 创建事件对象
    WSAEVENT hEvent = WSAEventCreate(NULL, TRUE, TRUE, NULL);
    

完成端口模型

简介

        完成端口模型是 Windows Sockets 中最复杂但也是最强大的 I/O 模型。它充分利用了多核处理器的能力,提供了一个可伸缩的高性能 I/O 操作解决方案。与其他 I/O 模型相比,完成端口模型具有以下优势:

  • **高性能:**完成端口模型可以充分利用多核处理器的能力,显著提高 I/O 操作的性能。
  • **可伸缩性:**完成端口模型可以处理大量并发连接,并随着硬件的升级而扩展。
  • **低延迟:**完成端口模型可以提供低延迟的 I/O 操作,非常适合对延迟敏感的应用程序。
工作原理

        完成端口模型的核心是使用 CreateIoCompletionPort 函数创建一个或多个完成端口。完成端口是一个内核对象,用于存储已完成 I/O 操作的通知。应用程序可以使用 AssociateSocket 函数将一个或多个套接字与完成端口关联起来。

        当一个套接字上的 I/O 操作完成时,系统会将一个 IO_COMPLETION_RESULT 结构体发送到与该套接字关联的完成端口。应用程序可以使用 GetQueuedCompletionPort 函数来检索完成端口队列中的通知。

主要步骤
  1. **创建完成端口:**使用 CreateIoCompletionPort 函数创建一个或多个完成端口。
  2. **关联套接字:**使用 AssociateSocket 函数将一个或多个套接字与完成端口关联起来。
  3. **发起 I/O 操作:**使用 WSASendWSARecv 等函数发起 I/O 操作,并将 OVERLAPPED 结构体传递给这些函数。
  4. **检索完成通知:**使用 GetQueuedCompletionPort 函数检索完成端口队列中的通知。
  5. **处理完成通知:**根据 IO_COMPLETION_RESULT 结构体中的信息处理完成的 I/O 操作。
线程池

        完成端口模型通常与线程池技术结合使用。线程池是一种管理线程的技术,可以有效地分配处理器资源进行并行计算。在完成端口模型中,应用程序可以使用线程池来处理完成的 I/O 操作。每个线程池中的线程都可以从完成端口队列中检索通知并处理完成的 I/O 操作。

应用场景

完成端口模型适用于需要处理大量并发 I/O 操作的应用程序,例如:

  • **网络应用程序:**Web 服务器、高性能网络应用、游戏服务器等。
  • **文件 I/O 密集型应用程序:**数据库应用程序、视频编辑软件、大型文件传输应用程序等。
示例代码

以下代码演示了如何使用完成端口模型从套接字中接收数据:

#include <winsock.h>

int main() {
    // 初始化 Winsock
    WSADATA wsaData;
    int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed: %d\n", iResult);
        return 1;
    }

    // 创建完成端口
    HANDLE hCompletionPort = CreateIoCompletionPort(NULL, NULL, 0, 0);
    if (hCompletionPort == NULL) {
        printf("CreateIoCompletionPort failed: %d\n", GetLastError());
        WSACleanup();
        return 1;
    }

    // 创建套接字
    SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock == INVALID_SOCKET) {
        printf("socket failed: %d\n", WSAGetLastError());
        CloseHandle(hCompletionPort);
        WSACleanup();
        return 1;
    }

    // 绑定套接字
    sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(8080);
    serverAddr.sin_addr.s_addr = INADDR_ANY;

    int iBindResult = bind(sock, (SOCKADDR*)&serverAddr, sizeof(serverAddr));
    if (iBindResult == SOCKET_ERROR) {
        printf("bind failed: %d\n", WSAGetLastError());
        closesocket(sock);
        CloseHandle(hCompletionPort);
        WSACleanup();
        return 1;
    }

    // 监听套接字
    int iListenResult = listen(sock, 5);
    if (iListenResult == SOCKET_ERROR) {

结论


        Winsock为Windows下的网络编程提供了多样化的I/O模型,每种模型都适用于不同场景的需求。无论是简单的select模型,还是高效的完成端口模型,了解它们的工作方式、优缺点对于开发高质量的网络应用程序都至关重要。掌握这些I/O模型,将有助于你建构出更稳定、更高性能的网络通信解决方案。

标签:socket,可扩展性,模型,sock,应用程序,Winsock,Select,SOCKET
From: https://blog.csdn.net/JAZJD/article/details/139156497

相关文章

  • 大语言模型发展历史
    大语言模型的发展历史可以追溯到自然语言处理(NLP)和机器学习早期的探索,但真正快速发展起来是在深度学习技术兴起之后。以下是大语言模型发展的一个简要历史概述:早期阶段(20世纪50-90年代):语言模型的概念最初源于20世纪50年代的信息论与概率论的融合,主要用于统计语言的规律。早......
  • 书生·浦语大模型全链路开源体系笔记
    大模型成为发展通用人工智能的重要途径专用模型专用模型:针对特定任务,一个模型解决一个问题。通用大模型:一个模型应对多种任务、多种模态。书生·浦语大模型开源历程书生·浦语2.0(InternLM2)的体系面向不同的使用需求,每个规格包含三个模型版本。7B:为轻量级的研......
  • 想转行做大模型?AI产品经理们,先看看这份指南
    如果你想转行做大模型,作为一名AI产品经理,你可以怎么做呢?或许,你可以先进行自我检测,看看自己是否真的适合转行做大模型。这篇文章里,作者便给想转行做大模型的AI产品经理们提出了一些建议,不妨来看看吧。作为一个产品经理,你可能已经熟悉了一些常见的AI技术和应用,比如机器学......
  • 回顾·总结·展望「融合RL与LLM思想,探寻世界模型以迈向AGI」
    导读:距离整篇「融合RL与LLM思想,探寻世界模型以迈向AGI」文章完稿分享已经过去了差不多一个月时间,在这期间,不管是在AI产业界还是在学术界,几乎每天都在经历着一幕幕令人惊艳而又期待的变化,变化包括了对模型算法的一次次突破和创新,包括了算法创新背后所对应的基础理论上的新......
  • LLM 大模型学习必知必会系列(六):量化技术解析、QLoRA技术、量化库介绍使用(AutoGPTQ、A
    LLM大模型学习必知必会系列(六):量化技术解析、QLoRA技术、量化库介绍使用(AutoGPTQ、AutoAWQ)模型的推理过程是一个复杂函数的计算过程,这个计算一般以矩阵乘法为主,也就是涉及到了并行计算。一般来说,单核CPU可以进行的计算种类更多,速度更快,但一般都是单条计算;而显卡能进行的......
  • LLM 大模型学习必知必会系列(十一):大模型自动评估理论和实战以及大模型评估框架详解
    LLM大模型学习必知必会系列(十一):大模型自动评估理论和实战以及大模型评估框架详解0.前言大语言模型(LLM)评测是LLM开发和应用中的关键环节。目前评测方法可以分为人工评测和自动评测,其中,自动评测技术相比人工评测来讲,具有效率高、一致性好、可复现、鲁棒性好等特点,逐渐成......
  • 如何让大模型更聪明?详解受益匪浅。
    一、前言在人工智能领域,大模型已经成为了一种趋势,它们凭借强大的学习和推理能力,在多个领域取得了显著的成果。然而,如何进一步提升大模型的智能水平,使其更好地服务于人类社会,成为了当前研究的热点。本文将围绕算法创新展开讨论,探讨如何通过创新算法让大模型更加聪明。二、算......
  • Ollama+Open WebUI本地搭建大模型并发布公网分享好友体验AI交互
    文章目录前言1.运行Ollama2.安装OpenWebUI2.1在Windows系统安装Docker2.2使用Docker部署OpenWebUI3.安装内网穿透工具4.创建固定公网地址前言本文主要介绍如何在Windows系统快速部署Ollama开源大语言模型运行工具,并安装OpenWebUI结合cpolar内网穿透软件,实......
  • AI大模型怎么学?你算问对人了
    AI大模型发展得如火如荼,可以遇见未来的千行百业都会被AI重塑,想要跟上AI科技发展的浪潮,唯有学习AI,认识AI,应用AI。于是整理了目前市面上关于AI大模型的学习资料,供你学习时选择适合自己的资料。遗憾的是书籍和课程笔者未全部看过(后续会继续分享AI实践、已阅书籍和学习课程的相......
  • 如何系统的入门大模型?
    对大模型领域感兴趣的程序员。看一下围绕大模型的应用场景和人才需求:pormpt:基于提示词对大模型的使用,会问问题就行。基于大模型的应用:在大模型生态之上做业务层产品。AI主播、AI小助手。。。之前是会调API就行。现在有了GPTs,连调用API都可以不用了,动动嘴就可以实现应用生......