Freertos源碼分析:任務創建/刪除

任務創建/刪除流程

1.簡介

FreeRTOS 中任務創建通過 xTaskCreate()xTaskCreateStatic() 實現。動態創建(xTaskCreate)會自動分配任務棧和TCB(任務控制塊),靜態創建(xTaskCreateStatic)需用戶預分配內存。

動態創建流程:

  • 參數校驗:檢查棧深度、任務函數指針等有效性。
  • 內存分配:調用 pvPortMalloc 分配TCB和棧空間。
  • TCB初始化:填充任務名、優先級、棧指針等字段。
  • 棧初始化:調用 pxPortInitialiseStack 模擬中斷壓棧,構造初始上下文。
  • 任務就緒:將任務加入就緒列表,觸發調度(若調度已啟動)。

任務刪除流程:任務刪除通過 vTaskDelete() 實現,支持刪除其他任務或自身(傳參 NULL)。刪除后資源需由空閑任務回收。

核心步驟:

  • 任務狀態檢查:若刪除自身標記為待刪除狀態并觸發調度;否則直接從就緒/阻塞列表移除。
  • 資源釋放:TCB和棧內存由空閑任務通過 prvDeleteTCB() 釋放。
  • 調度觸發:若刪除高優先級任務,可能引發上下文切換。
2.任務控制塊/鏈表項:
typedef struct tskTaskControlBlock       
{volatile StackType_t * pxTopOfStack; #if ( portUSING_MPU_WRAPPERS == 1 )xMPU_SETTINGS xMPUSettings; #endifListItem_t xStateListItem;                     //鏈表項,后面會加入任務的狀態鏈表ListItem_t xEventListItem;                     //鏈表項,后頁面會加入信號量,消息隊列等鏈表  UBaseType_t uxPriority;                        //任務優先級                StackType_t * pxStack;                         //任務棧的起點               char pcTaskName[ configMAX_TASK_NAME_LEN ];    //任務名,可以為空吧#if ( configUSE_TRACE_FACILITY == 1 )          //trace時使用UBaseType_t uxTCBNumber;  UBaseType_t uxTaskNumber; #endif#if ( configUSE_MUTEXES == 1 )                //互斥時使用--初始優先級和繼承優先級UBaseType_t uxBasePriority; UBaseType_t uxMutexesHeld;#endif#if ( configUSE_TASK_NOTIFICATIONS == 1 )     //任務通知使用--存放任務通知的值和狀態volatile uint32_t ulNotifiedValue[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];volatile uint8_t ucNotifyState[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];#endif} tskTCB;
struct xLIST_ITEM
{listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE          configLIST_VOLATILE TickType_t xItemValue;                //鏈表值,用于鏈表排序struct xLIST_ITEM * configLIST_VOLATILE pxNext;           //指向后一個鏈表項struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;       //指向前一個鏈表項void * pvOwner;                                           //一般用于存放TCB指針                                    struct xLIST * configLIST_VOLATILE pxContainer;           //用于存包含此鏈表項的鏈表的指針listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE          
};
3.任務創建/刪除(下文只分析動態創建的):

為什么推薦使用動態創建:

  • 我是用的芯片為f407,ram空間為:192K的----包括64K的CCM(僅CPU可訪問)、112K的SRAM1(主RAM)和16K的SRAM2(外設使用)。空間足夠大可以直接用heap4管理。
  • heap4提供了空間管理回收,若是自己分配還需要自己釋放,檢查是否溢出
/***************************************************************
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,                          //回調函數名/地址const char * const pcName,                      //任務名字const configSTACK_DEPTH_TYPE usStackDepth,      //任務棧大小,單位4bytevoid * const pvParameters,                      //回調函形參UBaseType_t uxPriority,                         //任務優先級,數值越大,優先級越高TaskHandle_t * const pxCreatedTask )            //任務控制塊地址/句柄
********************************************************************/

代碼分析:

1.xTaskCreate
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,const char * const pcName, const configSTACK_DEPTH_TYPE usStackDepth,void * const pvParameters,UBaseType_t uxPriority,TaskHandle_t * const pxCreatedTask ){TCB_t * pxNewTCB;BaseType_t xReturn;#if ( portSTACK_GROWTH > 0 )                                //增棧{************************************}#else                                                       //減棧{StackType_t * pxStack;  /*-------------------------申請任務棧空間-----------------------*/         pxStack = pvPortMallocStack((((size_t)usStackDepth)*sizeof( StackType_t ) ) );if( pxStack != NULL )                                   //如果申請棧空間成功{   /*---------------------申請TCB空間-------------------*/             pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); if( pxNewTCB != NULL )                              //如果TCB空間申請成功{memset((void*)pxNewTCB,0x00,sizeof(TCB_t));     //清空TCB空間pxNewTCB->pxStack = pxStack;                    //TCB->pxStack初始化}else {vPortFreeStack( pxStack );}                   //申請TCB空間失敗}else      pxNewTCB = NULL;                              //申請任務棧空間失敗}#endif /* portSTACK_GROWTH */if(pxNewTCB != NULL)                                        //TCB和棧空間都申請成功{prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL );          //初始化任務TCB以及棧prvAddNewTaskToReadyList( pxNewTCB );                   //將任務添加到就緒鏈表xReturn = pdPASS;}else xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;       //申請空間失敗          return xReturn;                                             //返回}
/*------------------------------------------------------------------------------------*/
1.1調用函數分析:

?prvInitialiseNewTask()

static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,const char * const pcName, const uint32_t ulStackDepth,void * const pvParameters,UBaseType_t uxPriority,TaskHandle_t * const pxCreatedTask,TCB_t * pxNewTCB,const MemoryRegion_t * const xRegions )
{StackType_t * pxTopOfStack;UBaseType_t x;/*------------------------初始化任務棧,每byte都為0xa5,檢查棧溢出使用----------------------*/#if ( tskSET_NEW_STACKS_TO_KNOWN_VALUE == 1 ){       (void)memset(pxNewTCB->pxStack,(int)tskSTACK_FILL_BYTE,(size_t)ulStackDepth * sizeof(StackType_t));}#endif 
/*------------------------------------------------------------------------------------*/    /*------------------如果是滿減棧:找出棧頂位置(高地址),對齊-------------------------------*/#if ( portSTACK_GROWTH < 0 ){pxTopOfStack = &(pxNewTCB->pxStack[ulStackDepth-(uint32_t)1]);pxTopOfStack = (StackType_t *)(((portPOINTER_SIZE_TYPE)pxTopOfStack)&(~(( portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK))); configASSERT(((portPOINTER_SIZE_TYPE)pxTopOfStack&(portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK)==0UL));}#else /* portSTACK_GROWTH */*****************************#endif /* portSTACK_GROWTH */
/*-----------------------------------------------------------------------------------*//*-------------------如果任務名不為NULL,TCB->pcTaskName初始化--------------------------*/if( pcName != NULL ){for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ ){pxNewTCB->pcTaskName[ x ] = pcName[ x ];          if( pcName[ x ] == ( char ) 0x00 ){break;}else{mtCOVERAGE_TEST_MARKER();}}      pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0';}else{mtCOVERAGE_TEST_MARKER();}
/*----------------------------------------------------------------------------------*//*------------任務優先級設置:如果任務優先級大于最大優先級,設置為最大優先級configASSERT( uxPriority < configMAX_PRIORITIES );if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES ){uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;}else{mtCOVERAGE_TEST_MARKER();}pxNewTCB->uxPriority = uxPriority;
/*----------------------------------------------------------------------------------*/    /*--------------------------如果設置了互斥,記錄原優先級-------------------------------*/#if ( configUSE_MUTEXES == 1 ){pxNewTCB->uxBasePriority = uxPriority;}#endif /* configUSE_MUTEXES */
/*---------------------------------------------------------------------------------*//*------------鏈表項初始化,清除鏈表項中pxContainer,表示未加入任何鏈表------------------*/vListInitialiseItem( &( pxNewTCB->xStateListItem ) );vListInitialiseItem( &( pxNewTCB->xEventListItem ) );
/*---------------------------------------------------------------------------------*/ /*將TCB指針放入鏈表項StateListItem,EventListItem,優先級和最高優先級的差放入xEventListItem-*/   listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB );    listSET_LIST_ITEM_VALUE( &( pxNewTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority );listSET_LIST_ITEM_OWNER( &( pxNewTCB->xEventListItem ), pxNewTCB );
/*---------------------------------------------------------------------------------*/#if ( portUSING_MPU_WRAPPERS == 1 ){**********************************}#else  ( void ) xRegions;#endif/*--------------------------------TCB初始化-------------------------------------*/   #if ( portUSING_MPU_WRAPPERS == 1 ){       ********************************}#else /* portUSING_MPU_WRAPPERS */{#if ( portHAS_STACK_OVERFLOW_CHECKING == 1 ){****************************************}#else                                                 //獲取棧頂{pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );}#endif /* portHAS_STACK_OVERFLOW_CHECKING */}#endif 
/*----------------------------TCB地址存入pxCreatedTask--------------------------*/if( pxCreatedTask != NULL ){*pxCreatedTask = ( TaskHandle_t ) pxNewTCB;}else{mtCOVERAGE_TEST_MARKER();}
}
/*------------------------------------------------------------------------------------*/

prvAddNewTaskToReadyList( )

static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB )
{taskENTER_CRITICAL();                                               //進入臨界緩沖區{uxCurrentNumberOfTasks++;
/*-----------------------------------如果當前沒有任務-----------------------------------*/if( pxCurrentTCB == NULL ){pxCurrentTCB = pxNewTCB;if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 )           //如果這是第一個任務{             prvInitialiseTaskLists();}else{mtCOVERAGE_TEST_MARKER();}}
/*---------------------------------------當前有的任務-----------------------------------*/else{           if( xSchedulerRunning == pdFALSE )                          //如果沒有開啟調度{/*--如果新任務優先級高于或者等于當前任務,當前任務設置為新任務--*/if( pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority ){pxCurrentTCB = pxNewTCB;}else   mtCOVERAGE_TEST_MARKER();                             }else      //如果開啟調度,不需要更換當前任務{mtCOVERAGE_TEST_MARKER();                              }}uxTaskNumber++;                                                 //統計任務數量#if ( configUSE_TRACE_FACILITY == 1 ){pxNewTCB->uxTCBNumber = uxTaskNumber;                       //TCB中記錄自己序號}#endif /* configUSE_TRACE_FACILITY */traceTASK_CREATE( pxNewTCB );prvAddTaskToReadyList( pxNewTCB );portSETUP_TCB( pxNewTCB );}taskEXIT_CRITICAL();                                                //退出臨界緩沖區if( xSchedulerRunning != pdFALSE )                                  //如果調度開啟{        if( pxCurrentTCB->uxPriority < pxNewTCB->uxPriority )           //新加入任務優先級高{taskYIELD_IF_USING_PREEMPTION();                   //喚醒任務切換-喚醒pendsv中斷}else                                                   //新任務優先級低,不理會{mtCOVERAGE_TEST_MARKER();}}else                                                       //如果任務調度沒開啟,不予理會{mtCOVERAGE_TEST_MARKER();}
}
/*-----------------------------------------------------------*/

    代碼片段:

    void vTaskDelete( TaskHandle_t xTaskToDelete ) {TCB_t *pxTCB;// 獲取待刪除任務的TCBpxTCB = prvGetTCBFromHandle( xTaskToDelete );// 從狀態列表中移除uxListRemove( &( pxTCB->xStateListItem ) );// 如果是刪除自身,標記為待刪除并觸發調度if( xTaskToDelete == NULL ) {vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xStateListItem ) );portYIELD();} else {prvDeleteTCB( pxTCB );}
    }
    
    2.xTaskCreate()
        void vTaskDelete( TaskHandle_t xTaskToDelete ){TCB_t * pxTCB;taskENTER_CRITICAL();                                     //進入臨界區{pxTCB = prvGetTCBFromHandle( xTaskToDelete );         //判斷刪除自身還是別的任務      
    /*------------------------------將任務從其狀態鏈表中移除------------------------------*/if( uxListRemove(&(pxTCB->xStateListItem))==(UBaseType_t)0){taskRESET_READY_PRIORITY( pxTCB->uxPriority );    //將其從就緒鏈表中移除}else{mtCOVERAGE_TEST_MARKER();}
    /*--------------------------------如果任務在等待事件---------------------------------*/if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ){( void ) uxListRemove( &( pxTCB->xEventListItem ) );  //將事件從其鏈表中移除}else{mtCOVERAGE_TEST_MARKER();}uxTaskNumber++;                                        //任務數量依舊增加
    /*--------------------------------如果待刪除任務是當前任務---------------------------*/if( pxTCB == pxCurrentTCB ){/*-------任務放入終止鏈表中,后續在idle任務中刪除--------*/vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xStateListItem ) );/*----增加此值,目的是idle任務可以知道有任務需要刪除-----*/++uxDeletedTasksWaitingCleanUp;        /*---window模式使用,arm不用理會----*/traceTASK_DELETE( pxTCB );portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending );}
    /*-------------------------------如果待刪除任務不是當前任務---------------------------*/else{--uxCurrentNumberOfTasks;                          //減少當前任務數量traceTASK_DELETE( pxTCB );                        prvResetNextTaskUnblockTime();                     //重置解除阻塞時間}}taskEXIT_CRITICAL();                                       //退出臨界保護
    /*----------------如果要刪除的任務不是當前任務,直接刪除TCB,釋放空間--------------------*/if( pxTCB != pxCurrentTCB ){prvDeleteTCB( pxTCB );}
    /*----------------------------如果調度器重新開始計時調度-----------------------------*/if( xSchedulerRunning != pdFALSE ){if( pxTCB == pxCurrentTCB ){configASSERT( uxSchedulerSuspended == 0 );portYIELD_WITHIN_API();}else{mtCOVERAGE_TEST_MARKER();}}}
    

    關鍵函數說明

    • prvInitialiseNewTask():初始化TCB結構,包括棧頂指針、任務入口、優先級鏈表等。
    • prvAddNewTaskToReadyList():將任務加入就緒列表,若優先級高于當前任務則觸發調度。
    • prvDeleteTCB():釋放TCB和棧內存(動態創建時),靜態創建需用戶手動釋放。
    注意事項
    • 刪除任務時需確保其未持有信號量、隊列等資源,否則可能導致內存泄漏。
    • 靜態創建任務需保證預分配內存生命周期覆蓋任務運行周期。

    本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
    如若轉載,請注明出處:http://www.pswp.cn/bicheng/89775.shtml
    繁體地址,請注明出處:http://hk.pswp.cn/bicheng/89775.shtml
    英文地址,請注明出處:http://en.pswp.cn/bicheng/89775.shtml

    如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

    相關文章

    warning: _close is not implemented and will always fail

    相關問題&#xff1a; 一、undefined reference to _exit undefined reference to ‘end‘ warning: _close is not implemented and will always fail 一、環境&#xff1a; ubuntu24.04實體機、 arm-none-eabi-gcc gcc version 13.2.1 20231009 (15:13.2.rel1-2) 二…

    MyBatis之緩存機制詳解

    MyBatis之緩存機制詳解一、MyBatis緩存的基本概念1.1 緩存的核心價值1.2 MyBatis的兩級緩存體系二、一級緩存&#xff08;SqlSession級別緩存&#xff09;2.1 工作原理2.2 實戰案例&#xff1a;一級緩存演示2.2.1 基礎用法&#xff08;默認開啟&#xff09;2.2.2 一級緩存失效場…

    云服務器搭建自己的FRP服務。為什么客戶端的項目需要用Docker啟動,服務端才能夠訪問到?

    簡單回答&#xff1a;在云服務器搭建FRP服務時&#xff0c;客戶端項目用Docker啟動并非必需&#xff0c;而是因為Docker的特性簡化了配置&#xff1a; Docker通過端口映射&#xff08;如-p 本地端口:容器端口&#xff09;能固定項目對外暴露的端口&#xff0c;減少本地端口沖突…

    6 STM32單片機的智能家居安防系統設計(STM32代碼+手機APP設計+PCB設計+Proteus仿真)

    系列文章目錄 文章目錄 系列文章目錄前言1 資料獲取與演示視頻1.1 資料介紹1.2 資料獲取1.3 演示視頻 2 系統框架3 硬件3.1 主控制器3.2 顯示屏3.3 WIFI模塊3.4 DHT11溫濕度傳感器3.5 煙霧/燃氣傳感器模塊&#xff1a;MQ-23.6 火焰傳感器3.7 門磁模塊MC-38 4 設計PCB4.1 安裝下…

    DevOps落地的終極實踐:8大關鍵路徑揭秘!

    本文來自騰訊藍鯨智云社區用戶: CanWay當前&#xff0c;DevOps因其能夠降低IT運營成本、提高軟件質量并加快上市時間的能力而在全球范圍內引起廣泛關注。它打破了傳統軟件開發與運營的界限&#xff0c;消除了新功能發布延遲和軟件質量下降的障礙。DevOps通過實施持續集成、持續…

    react - 根據路由生成菜單

    后端返回菜單的格式menuList:[{index: true,name: "",component: "../views/Home",meta: { title: "首頁", requiresAuth: true,roles:[user]},},{path: "/admin",name: "admin",meta: { title: "管理頁", roles:…

    Window延遲更新10000天配置方案

    1.點擊"開始"菜單&#xff0c;搜索"注冊表編輯器"&#xff0c;點擊"打開"。2.找到"\HKEY LOCAL MACHINE\SOFTWARE\Microsoft\WindowsUpdate\Ux\Settings"路徑。3.右面空白處右鍵新建一個32位值&#xff0c;命名為FlightSettingsMaxPau…

    【OD機試】人民幣轉換

    題目描述 將阿拉伯數字金額轉換為中文大寫金額格式,需遵循以下規則: 1、 前綴要求:中文大寫金額前必須標明“人民幣”字樣。 2、 用字規范:使用壹、貳、叁、肆、伍、陸、柒、捌、玖、拾、佰、仟、萬、億、元、角、分、零、整等字樣。 3、 “整”字規則: 金額到“元”為止…

    在ajax中什么時候需要將返回值類型做轉換

    $.ajax({url: TMSPROC0050/deleteData?accidentIds accidentIds.join(,),type: DELETE,dataType: json,success: function(result) {$(#accidentGrid).datagrid(reload);$.messager.show({title: 成功,msg: result.message})},error: function(result) {$.messager.alert({ti…

    Helm常用命令大全(2025最新版)

    文章目錄Helm常用命令大全&#xff08;2025最新版&#xff09;一、基礎命令與環境配置版本與幫助信息安裝與升級HelmLinux系統安裝版本升級注意事項二、倉庫管理命令倉庫基礎操作OCI倉庫支持&#xff08;v3.8新特性&#xff09;三、Chart操作命令Chart創建與打包Chart搜索與下載…

    gitlab+jenkins

    文章目錄架構gitlab和jenkins安裝jenkins配置gitlab配置jenkins與gitlab聯動參考架構 gitlab和jenkins安裝 部署docker 部署jenkins 啟動jenkins 用戶&#xff1a;admin&#xff0c;對應的密碼如下 點擊安裝自定義推薦的插件 安裝gitlab插件 jenkins配置 配置pipline…

    Redis字符串操作指南:從入門到實戰應用

    Redis作為一款高性能的鍵值存儲數據庫&#xff0c;其字符串&#xff08;String&#xff09;類型是最基礎也最常用的數據類型。它不僅能存儲簡單的文本信息&#xff0c;還能應對數字計算、二進制數據等多種場景&#xff0c;靈活且高效。接下來&#xff0c;我們就全方位剖析Redis…

    SQLite 數據庫字段類型-詳細說明,數據類型詳細說明。

    SQLite 數據類型 SQLite字段類型詳細說明&#xff0c;包含存儲類、親和類型、布爾類型、日期時間類型的存儲方式、取值范圍及核心特性。 創建 SQLite3 表時可使用的各種數據類型名稱&#xff0c;同時也介紹了相應的親和類型。 一、核心存儲類&#xff08;Storage Classes&am…

    Node.js特訓專欄-實戰進階:17.會話管理與安全存儲

    ?? 歡迎來到 Node.js 實戰專欄!在這里,每一行代碼都是解鎖高性能應用的鑰匙,讓我們一起開啟 Node.js 的奇妙開發之旅! Node.js 特訓專欄主頁 專欄內容規劃詳情 會話管理與安全存儲:從原理到實戰的Web安全實踐 在Web應用中,會話(Session)是維持用戶狀態的核心機制—…

    【橘子分布式】gRPC(編程篇-中)

    一、簡介 我們之前已經完成了對于api模塊的開發&#xff0c;也就是已經生成了基礎的類和對應的接口&#xff0c;現在我們需要完成的是client和server端的開發。其實如同thrift一樣&#xff0c;現在要做的就是實現我們之前定義的service里面的hello方法&#xff0c;里面寫我們的…

    Spring Boot 項目中數據同步之binlog和MQ

    在 Spring Boot 項目中&#xff0c;“監聽 binlog” 和 “業務代碼中集成 MQ” 是實現數據同步、事件驅動的兩種主流方法。 簡單來說&#xff0c;這個選擇可以概括為&#xff1a; 監聽 Binlog (如使用 Canal)&#xff1a;像一個數據庫的貼身秘書&#xff0c;它忠實地記錄數據庫…

    MySQL 寫入性能優化全攻略(附 GitHub 面試題項目鏈接)

    面試中你可能會遇到這樣的問題&#xff1a; &#x1f4ac; “假設你的接口一天收到百萬級請求&#xff0c;MySQL 撐得住嗎&#xff1f;你會怎么優化寫入性能&#xff1f;” 剛開始我也懵過&#xff0c;后來不斷復盤與總結&#xff0c;現在我可以用結構化方式給出一個相對完整的…

    用Dynamic chunk去干掉tokenizer?

    一般你們下AR模型的時候&#xff0c;都有這個&#xff0c;也就是tokenzier&#xff0c;tokenizer是干啥的&#xff0c;其實就是你的分詞字典不光有specal的token對應的還有實際的對應的分詞對應的代碼&#xff0c;比如&#xff1a;也有tokenzier沒顯示的&#xff0c;比如&#…

    Linux系統日志管理入門:journalctl命令完全指南

    Linux系統日志管理入門&#xff1a;journalctl命令完全指南前言一、journalctl介紹二、基礎使用&#xff1a;快速上手1. 查看全部日志2. 查看本次啟動的日志3. 按時間篩選日志4. 按服務&#xff08;單元&#xff09;過濾日志三、常用參數與場景四、實戰案例&#xff1a;解決實際…

    神經網絡的基本骨架——nn.Module的使用(torch.nn庫)

    在 PyTorch 中&#xff0c;nn.Module 是所有神經網絡模塊的基類&#xff0c;用于構建和組織深度學習模型。它提供了一系列工具和功能&#xff0c;使模型的定義、訓練和部署更加高效和靈活。nn Neural Network&#xff08;神經網絡&#xff09;核心作用&#xff1a;模塊化設計&…