FreeRTOS_任务基础知识

news2024/11/28 0:39:49

目录

1. 什么是多任务系统?

2. FreeRTOS 任务与协程

2.1 任务 (Task) 的特性

2.2 协程(Co - routine)的特性

3. 任务状态

4. 任务优先级

5. 任务实现

6. 任务控制块

7. 任务堆栈


        RTOS 系统的核心就是任务管理,FreeRTOS 也不例外,我们学习 RTOS 主要是为了使用 RTOS 的多任务处理功能;首先要做的就是必须掌握任务的创建、删除、挂起和恢复等操作,由此可见任务管理的重要性。

1. 什么是多任务系统?

        我们之前在学习51单片机、STM32单片机裸机(未使用系统)的时候,一般都是在 main 函数里面用 while(1) 做一个大循环来完成所有的处理,也就是说应用程序是一个无限的循环,在循环中调用相应的函数完成所需的处理,有的时候我们也会在中断里面添加一些函数完成一些处理。

        相对于多任务系统而言,这个就是单任务系统,也称作前后台系统,中断服务函数作为前台程序,大循环 while(1) 作为后台程序。

        前后台系统的实时性差,前后台系统各个任务(应用程序)都是排队等着轮流执行,不管你这个程序现在有多紧急,没轮到你就只能等着!相当于所有任务(应用程序)的优先级都是一样的。但是前后台系统的优点明显是简单,而且资源消耗的也少!但是在稍微大一点的嵌入式应用中前后台系统就明显力不从心了,此时就需要多任务系统出马了。

        多任务系统会把一个大问题(应用) “分而治之” ,把大问题划分成很多个小问题,逐步地把小问题解决掉,大问题也就随之解决了,这些小问题可以单独的作为一个小任务来处理。这小任务是并发处理的,注意,并不是说同一时刻一起执行很多个任务,而是由于每个任务执行的时间很短,导致看起来像是同一时刻执行了很多个任务一样。(这就好比我们数学上的定积分是一样的,定积分处理的思想就是把无限长的曲线截成无限段,那么每一小段都可以近似的看做是直线,这样分别的处理每一小段进行叠加即可,多任务也是这样,大任务分成无限多的小任务,每一个小任务占用系统的时间很小,因此导致看起来像是同一时刻执行了很多个任务,但是实际上并不是这样,这里需要注意)

        多任务系统带来一个新的问题,究竟哪个任务先运行,哪个任务后运行呢?完成这个功能的东西在 RTOS系统中叫做任务调度器。不同的系统其任务调度器的实现方法也不同,比如 FreeRTOS 是一个抢占式的实时多任务系统,那么其任务调度器也是抢占式的

        在抢占式多任务系统中,高优先级的任务可以打断低优先级的任务的运行而取得 CPU 的使用权,这样就保证了那些紧急任务的运行。这样我们就可以为那些对实时性要求高的任务设置一个很高的优先级,比如自动驾驶中的障碍物检测任务等。高优先级的任务执行完成以后重新把 CPU 的使用权归还给低优先级的任务,这个就是抢占式多任务系统的基本原理

2. FreeRTOS 任务与协程

        在 FreeRTOS 中应用既可以使用任务,也可以使用协程(Co-Routine),或者两者混合使用。但是任务和协程使用不同的 API 函数,因此不能通过队列(或信号量)将数据从任务发送给协程,反之亦然。

什么叫 API 函数?

        API(Application Programming Interface,应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。    ——百度百科

        在文件系统中,以C语言为例,我们使用 fopen() 函数可以打开一个文件,在写程序时,我们感觉非常简单。文件保存在硬盘上,要经过复杂的处理才能显示,这些细节对于我们来说是透明的,使用操作系统来完成。也就是说,我们调用 fopen() 函数来通知操作系统,让操作系统来打开一个文件。

        那么如何告诉操作系统打开文件呢?

        其实看似简单的调用函数 fopen,实际上在底层是非常复杂的,打开文件首先要扫描硬盘,找到文件的位置,然后从文件中读取一部分数据,将数据放进 I/O 缓冲区,放进内存;这些数据都是 0 1 序列,操作系统还要对照ASCII表或Unicode表 “翻译” 成字符,然后再在显示器上显示出来。试想一下,如果这个过程让程序员来完成,简直是噩梦!!!

        基于此,操作系统想了一个办法,我把上述这一系列的打开文件的操作写在一个函数里,编译成一个组件(一般是动态链接库)随操作系统一起发布,并且附上说明文档,程序员只需要简单的调用这个函数就可以完成复杂的工作;这些封装好的函数,就叫做API(Application Programming Interface),即应用程序编译接口!

        说的更通俗易懂一点,就是别人写好的代码,或者编译好的程序,提供给我们使用,就叫做API。你使用了别人的代码(或者程序)中的某个函数、类、对象,就叫做使用了某个API

        例如:

        C语言 API 以函数的形式呈现,例如 printf()、scanf()、fopen() 等。

        Java API 主要以类的形式呈现,例如 String、Thread、Date 等。

2.1 任务 (Task) 的特性

        在使用 RTOS 的时候一个实时应用可以作为一个独立的任务。每个任务都有自己的运行环境,不依赖于系统中其他的任务或者 RTOS 调度器。任何一个时间点只能有一个任务运行,具体哪一个任务运行是由 RTOS 调度器来决定的,RTOS 调度器因此会重复的开启、关闭每个任务。(这一点在上面已经解释过了)

        任务不需要了解 RTOS 调度器的具体行为,RTOS 调度器的职责是确保当一个任务开始执行的时候其上下文环境(寄存器值,堆栈内容等)和任务上一次退出的时候相同。为了做到这一点,每个任务都必须有一个堆栈,当任务切换的时候将上下文环境保存在堆栈中,这样当任务再次执行的时候就可以从堆栈中取出上下文环境,任务恢复运行。

任务特性:

        1. 简单

        2. 没有使用限制

        3. 支持抢占

        4. 支持优先级

        5. 每个任务都拥有堆栈导致了 RAM 使用量增大

        6. 如果使用抢占的话必须仔细的考虑重入的问题

2.2 协程(Co - routine)的特性

        协程是为那些资源很少的 MCU 而做的,但是随着 MCU 的飞速发展,性能越来越强大,现在协程几乎很少用到了!(FreeRTOS 目前还没有打算把协程移出,但是也不会再更新和维护协程了)

在概念上协程和任务是相似的,但是有如下根本上的不同:

        1. 堆栈使用

        所有的协程使用同一个堆栈(但是如果是任务的话每个任务都有自己的堆栈),这样使用协程就比使用任务消耗更少的 RAM。

        2. 调度器和优先级

        协程使用合作式的调度器,但是可以在使用抢占式的调度器中使用协程。

        3. 宏定义

        协程是通过宏定义来实现的。

        4. 使用限制

        为了降低对 RAM 的消耗做了很多的限制。

3. 任务状态

        FreeRTOS 中的任务永远处于下面几个状态中的某一个:

运行态:

        当一个任务正在运行时,那么就说这个任务处于运行态,处于运行态的任务就是当前正在使用处理器的任务。如果使用的是单核处理器的话那么不管在任何时刻永远都只有一个任务处于运行态。

就绪态:

        处于就绪态的任务是那些已经准备就绪(这些任务没有被阻塞或者挂起),可以运行的任务,但是处于就绪态的任务还没有运行,因为有一个同优先级或者更高优先级的任务正在运行!

阻塞态:

        如果一个任务当前正在等待某个外部事件的话就说它处于阻塞态,比如说如果某个任务调用了函数 vTaskDelay() 的话就会进入阻塞态,直到延时周期完成。任务在等待队列、信号量、事件组、通知或互斥信号量的时候也会进入阻塞态。任务进入阻塞态会有一个超时时间,当超过这个超时时间就会退出阻塞态,即使所等待的事件还没有来临!

挂起态:

        像阻塞态一样,任务进入挂起态以后也不能被调度器调用进入运行态,但是进入挂起态的任务没有超时时间(也就是说任务不会自动退出挂起态)。任务进入和退出挂起态通过调用函数 vTaskSuspend() 和 xTaskPesume() 。

4. 任务优先级

        每个任务都可以分配一个从 0~(configMAX_PRIORITIES - 1) 的优先级,configMAX_PRIORITIES 在文件 FreeRTOSConfig.h 中有定义。如果所使用的硬件平台支持类似计算前导零这样的指令(可以通过该指令选择下一个要运行的任务,Cortex - M 处理器支持该指令),并且宏 configUSE_PORT_OPTIMISED_TASK_SELECTION 也就同时被设置为了 1 ,那么宏 configMAX_PRIORITIES 不能超过 32 !也就是优先级不能超过 32 级。其他情况下宏 configMAX_PRIORITIES 可以设置为任何值,但是考虑到 RAM 的消耗,宏 configMAX_PRIORITIES 最好设置为一个满足应用的最小值。

        优先级数字越低表示任务的优先级越低, 0 的优先级最低,configMAX_PRIORITIES - 1 的优先级最高。空闲任务的优先级最低,为 0 。

        FreeRTOS 调度器确保处于就绪态或运行态的高优先级的任务获取处理器使用权,换句话说就是处于就绪态的最高优先级的任务才会运行。当宏 configUSE_TIME_SLICING 定义为 1 的时候多个任务可以共用一个优先级,数量不限。默认情况下宏 configUSE_TIME_SLICING 在文件 FreeRTOS.h 中已经定义为 1 。此时处于就绪态的优先级相同的任务就会使用时间片轮转调度器获取运行时间。

5. 任务实现

        在使用 FreeRTOS 的过程中,我们要使用函数 xTaskCreate() 或 xTaskCreateStatic() 来创建任务,这两个函数的第一个参数 pxTaskCode,就是这个任务的任务函数

        什么是任务函数?任务函数就是完成本任务工作的函数。就是说我这个任务要干嘛?要做什么?要完成什么样的功能都是在这个任务函数中实现的。(比如说我要做个任务,这个任务要点个流水灯,那么这个流水灯的程序就是任务函数中实现的)

FreeRTOS 官方给出的任务函数模板如下:

void vATaskFunction(void *pvParameters)   (1)
{
    for(;;)                             (2)
    {
        --任务应用程序--                   (3)
        vTaskDelay();                     (4)
    }
    //不能从任务函数中返回或者退出,从任务函数中返回或者退出的话就会调用 configASSERT(),前提是我们定义了 configASSERT()。
    //如果一定要从任务函数中退出的话那一定要调用函数 vTaskDelete(NULL) 来删除此任务
    
    vTaskDelete(NULL);                    (5) 
}

        (1)、任务函数本质上也是函数,所以肯定也是有任务名什么的,不过这里我们需要注意:任务函数的返回类型一定要为 void 类型,也就是无返回值,而且任务的参数也是 void 指针类型的!任务函数名可以根据实际情况定义。

        (2)、任务的具体执行过程是一个大循环,for( ; ; ) 就表示一个循环,作用和 while(1) 一样,具体使用时根据个人习惯即可。

        (3)、循环里面就是真正的任务代码了,此任务具体要干的活就在这里实现!

        (4)、FreeRTOS 的延时函数,此处不一定要用延时函数,其他只要能让 FreeRTOS 发生任务切换的 API 函数都可以,比如请求信号量、队列等,甚至直接调用任务调度器。只不过最常用的还是 FreeRTOS 的延时函数。

        (5)、任务函数一般不允许跳出循环,如果一定要跳出循环的话在跳出循环以后一定要调用函数 vTaskDelete(NULL) 删除此任务!

        FreeRTOS 的任务函数和 UCOS 的任务函数模式基本上相同,不止 FreeRTOS,其他 RTOS 的任务函数基本上也是这种方式。

6. 任务控制块

        FreeRTOS 的每个任务都有一些属性需要存储,FreeRTOS 把这些属性集合到一起用一个结构体来表示,这个结构体叫做任务控制块:TCB_t,在使用函数 xTaskCreate() 创建任务的时候就会自动的给每一个任务分配一个任务控制块。在老版本的 FreeRTOS 中任务控制块叫做 tskTCB,新版本重命名为 TCB_t,但是本质上还是 tskTCB,对于 FreeRTOS 的学习中,凡是提到任务控制块的话均用 TCB_t 表示,此结构体在文件 task.c 中有定义;

/*
 * Task control block.  A task control block (TCB) is allocated for each task,
 * and stores task state information, including a pointer to the task's context
 * (the task's run time environment, including register values)
 */
/*
 * 任务控制块。为每个任务分配一个任务控制块(TCB),并存储任务状态信息,包括指向任务上下文的指针(任务的运行时环境,包括寄存器值)。 
 */
typedef struct tskTaskControlBlock
{
	volatile StackType_t	*pxTopOfStack;	/*< 任务堆栈栈顶 */
                                            //指向任务堆栈中最后一项的位置,这必须是 TCB 结构体的第一个成员
    //"Volatile"是C语言的一个关键字,它可以用于修饰某个变量,告诉编译器该变量的值可能随时会发生改变,因此在读取该变量的值时,应该直接从内存中获取,而不要使用缓存。

    //具体来说,当一个变量被声明为volatile时,意味着该变量可能被多个线程或进程同时访问,并且其值可能随时会被改变,因此编译器不能优化对该变量的访问方式,
    //而是始终直接从内存中读取该变量的值。这种变量的用途通常是用来存储硬件状态或者与硬件相关的变量,以保证程序正确地与硬件交互。
	#if ( portUSING_MPU_WRAPPERS == 1 )
    //宏定义#define portUSING_MPU_WRAPPERS 0
		xMPU_SETTINGS	xMPUSettings;		/*< MPU相关设置 */
	#endif                                  //MPU设置被定义为端口层的一部分。这必须是TCB结构体的第二个成员。

	ListItem_t			xStateListItem;	    /*< 任务的状态列表项引用的列表表示该任务的状态(就绪、阻塞、挂起) */  //状态列表项
	ListItem_t			xEventListItem;		/*< 用于从事件列表中引用任务。 */                                  //事件列表项
	UBaseType_t			uxPriority;			/*< 任务的优先级,0为最低的优先级 */                               //任务优先级
	StackType_t			*pxStack;			/*< 指向堆栈的起点 */                                              //任务堆栈起始位置
	char				pcTaskName[ configMAX_TASK_NAME_LEN ];/*< 创建时给任务的描述性名称。只方便调试。 */     //任务名字

	#if ( portSTACK_GROWTH > 0 ) //#define portSTACK_GROWTH			( -1 )
		StackType_t		*pxEndOfStack;Points to the start of the stack.		/*< 在堆栈从低内存增长的体系结构中,指向堆栈的末端。 */  //任务堆栈栈底
	#endif

	#if ( portCRITICAL_NESTING_IN_TCB == 1 ) //#define portCRITICAL_NESTING_IN_TCB 0
		UBaseType_t		uxCriticalNesting;	/*< 保存在端口层中不保持自己计数的端口的关键区域嵌套深度。 */  //临界区嵌套深度
	#endif

	#if ( configUSE_TRACE_FACILITY == 1 ) //#define configUSE_TRACE_FACILITY		1    //trace 或到 debug 的时候用到
		UBaseType_t		uxTCBNumber;		/*< 存储一个数字,每次创建TCB时该数字递增。它允许调试器确定任务何时被删除,然后重新创建。 */
		UBaseType_t		uxTaskNumber;		/*< 存储专门供第三方跟踪代码使用的数字。 */
	#endif

	#if ( configUSE_MUTEXES == 1 ) //#define configUSE_MUTEXES				1
		UBaseType_t		uxBasePriority;		/*< 最后分配给任务的优先级——由优先级继承机制使用。 */  //任务基础优先级,优先级反转的时候用到
		UBaseType_t		uxMutexesHeld;                                                             //任务获取到的互斥信号量个数 
	#endif

	#if ( configUSE_APPLICATION_TASK_TAG == 1 ) //#define configUSE_APPLICATION_TASK_TAG	0
		TaskHookFunction_t pxTaskTag;
	#endif

	#if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) //#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 0  //与本地存储有关
		void *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
	#endif

	#if( configGENERATE_RUN_TIME_STATS == 1 ) //#define configGENERATE_RUN_TIME_STATS	0
		uint32_t		ulRunTimeCounter;	/*< 存储任务在“运行”状态下花费的时间。 */  //用来记录任务运行总时间
	#endif

	#if ( configUSE_NEWLIB_REENTRANT == 1 ) //#define configUSE_NEWLIB_REENTRANT 0
		/* Allocate a Newlib reent structure that is specific to this task.
		Note Newlib support has been included by popular demand, but is not
		used by the FreeRTOS maintainers themselves.  FreeRTOS is not
		responsible for resulting newlib operation.  User must be familiar with
		newlib and must provide system-wide implementations of the necessary
		stubs. Be warned that (at the time of writing) the current newlib design
		implements a system-wide malloc() that must be provided with locks. */
        //分配一个特定于此任务的Newlib最近结构。注意:Newlib支持是根据大众需求包含的,但是FreeRTOS维护者自己并不使用。FreeRTOS不对由此产生的newlib操作负责。
        //用户必须熟悉newlib,并且必须提供必要存根的系统范围实现。请注意(在撰写本文时)当前的newlib设计
        //实现必须与锁一起提供的系统范围malloc()。
		struct	_reent xNewLib_reent;  //定义一个 newlib 结构体变量
	#endif

	#if( configUSE_TASK_NOTIFICATIONS == 1 ) //#define configUSE_TASK_NOTIFICATIONS 1  //任务通知相关变量
		volatile uint32_t ulNotifiedValue;                                             //任务通知值
		volatile uint8_t ucNotifyState;                                                //任务通知状态                     
	#endif  

	/* 请参阅上面关于tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE定义的注释。 */
	#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
    //用来标记任务是动态创建的还是静态创建的,如果是静态创建的此变量就为 pdTURE,如果是动态创建的就为 pdFALSE
    //#define tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE ( ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) || ( portUSING_MPU_WRAPPERS == 1 ) )
		uint8_t	ucStaticallyAllocated; 		/*< 如果任务是静态分配的,则设置为pdTRUE,以确保不尝试释放内存。 */
	#endif

	#if( INCLUDE_xTaskAbortDelay == 1 ) //#define INCLUDE_xTaskAbortDelay 0
		uint8_t ucDelayAborted;
	#endif

} tskTCB;

7. 任务堆栈

        FreeRTOS 之所以能正确的恢复一个任务的运行就是因为有任务堆栈在保驾护航,任务调度器在进行任务切换的时候会将当前任务的现场(CPU寄存器值等)保存在此任务的任务堆栈中,等到此任务下次运行的时候就会先用堆栈中保存的值来恢复现场,恢复现场以后任务就会接着从上次中断的地方开始运行。

        创建任务的时候需要给任务指定堆栈,如果使用的是函数 xTaskCreate() 创建任务(动态方法)的话那么任务堆栈就会由函数 xTaskCreate() 自动创建;

        如果使用函数 xTaskCreateStatic() 创建任务(静态方法)的话就需要程序员自行定义任务堆栈,然后堆栈首地址作为函数的参数 puxStackBuffer 传递给函数

TaskHandle_t xTaskCreateStatic(TaskFunction_t      pxTaskCode,                //任务函数 
                               const char *const   pcName,                    //任务名称
                               const uint32_t      ulStackDepth,              //任务堆栈大小
                               void *const         pvParameters,       //传递给任务函数的参数
                               UBaseType_t         uxPriority,                //任务优先级
                               StackType_t*        const puxStackBuffer, (1)
                               StaticTask_t*       const pxTaskBuffer  
                               )

(1)、任务堆栈,需要用户定义,然后将堆栈首地址传递给这个参数

堆栈大小:

        我们不管是使用函数 xTaskCreate() 动态创建还是 xTaskCreateStatic() 静态创建任务都需要指定任务堆栈大小。任务堆栈的数据类型为 StackType_t,StackType_t 本质上是 uint32_t,在 portmacro.h 中有定义,如下:

#define portSTACK_TYPE  uint32_t
#define portBASE_TYPE   long

typedef portSTACK_TYPE  StackType_t;
typedef long            BaseType_t;
typedef unsigned long   UBaseType_t;

        可以看出 StackType_t 类型的变量为 4 个字节,那么任务的实际堆栈大小就应该是我们所定义的 4 倍;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/615463.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

软件测试想要高薪资,不仅要卷还要学会跳槽

都说00后躺平了&#xff0c;但是有一说一&#xff0c;该卷的还是卷。 这不&#xff0c;前段时间我们公司来了个00后&#xff0c;工作都没两年&#xff0c;跳槽到我们公司起薪20K&#xff0c;都快接近我了。后来才知道人家是个卷王&#xff0c;从早干到晚就差搬张床到工位睡觉了…

C++ new和delete的使用

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、new和delete介绍二、简单使用1.new和delete2.自定义对象3.new[]和delete[]4.主存耗尽5.try&catch6.nothrow7.看下源代码 前言 new和delete是C里非常重…

【运维】服务器系统安装

目录 一、环境 二、ubuntu 三、启动u盘制作 Stage 1&#xff1a;下载balena&#xff0c;制作U盘启动工具 Stage 2&#xff1a;下载Ubuntu 系统镜像&#xff08;参考上一节&#xff1a;Ubuntu 22.04.2 LTS &#xff09; Stage 3&#xff1a;将镜像写入到U盘 四、设置开启…

6 面阿里、5 面字节、4 面腾讯,可算是入坑了····

8 年前&#xff0c;BAT 冲到了风口浪尖&#xff0c;美国上市的阿里成为中国体量最大的互联网公司&#xff0c;腾讯借助微信成为移动互联网的霸主&#xff0c;外企开始撤离中国&#xff0c;国企的光环也慢慢褪去。 到了近年&#xff0c;应届毕业生心中最炙手可热的公司换成了 T…

共话出海、布局全球,融云WICC2023 · 泛娱乐出海嘉年华广州收官!

&#xff08;移步公众号点击图片三折购买《社交泛娱乐出海作战地图》&#xff09; 6 月 2 日&#xff0c;“WICC 泛娱乐出海嘉年华”在广州成功举办&#xff0c;圆满收官。关注【融云全球互联网通信云】了解更多 本届嘉年华由高端峰会、圆桌会议、露营派对三部分组成&#xf…

资深8年测试,全链路压测与性能的优化详解,一文通透...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 什么是全链路压测…

了解CPU瓶颈原因,掌握代码优化、TOP命令及缓存技术,让服务器不再为性能瓶颈所困扰。

目录 前言&#xff1a; 一、CPU瓶颈原因分析 1. CPU使用率过高 2. 进程使用CPU过多 3. 磁盘I/O读写速度过慢 二、CPU瓶颈调优方案 1. 使用top命令查看CPU使用率 2. 优化程序设计 3. 使用缓存技术 总结&#xff1a; 前言&#xff1a; 在服务器运行过程中&#xff0c;…

干货 | 实战演练基于加密接口测试测试用例设计

如果接口测试仅仅只是掌握一些requests或者其他一些功能强大的库的用法&#xff0c;是远远不够的&#xff0c;还需要具有根据公司的业务以及需求去定制化一个接口自动化测试框架能力。所以在这个部分&#xff0c;会主要介绍接口测试用例分析以及通用的流程封装是如何完成的。 首…

GitHub 竟然有这些骚操作,真是涨姿势

GitHub 竟然有这些骚操作&#xff0c;真是涨姿势 GitHub&#xff0c;不用过多介绍。一个面向开源及私有软件项目的托管平台&#xff0c;因为只支持 git 作为唯一的版本库格式进行托管&#xff0c;故名 GitHub。 作为「全球最大的程序员“交友”社区」&#xff0c;程序员的你&am…

入门AI从谷歌这10门独立课程开始

​ 谷歌最近发布了一个名为"Generative AI learning path"的学习路径&#xff0c;该路径专为初学者设计&#xff0c;共包含10门独立课程。通过这个学习路径&#xff0c;初学者可以从基础概念开始学习&#xff0c;并逐步深入到更复杂的主题&#xff0c;帮助他们了解生…

NLP实战:调用Gensim库训练Word2Vec模型

目录 一、准备工作 1. 安装Gensim库 2. 对原始语料分词 二、训练Word2Vec模型 三、模型应用 1.计算词汇相似度 ​编辑 2. 找出不匹配的词汇 3. 计算词汇的词频 四、总结 &#x1f368; 本文为[&#x1f517;365天深度学习训练营]内部限免文章&#xff08;版权归 *K同学…

第7章:SpringMVC的HttpMessageConverter

1. HttpMessageConverter简介 ①HttpMessageConverter&#xff0c;报文信息转换器&#xff0c;将请求报文转换为java对象&#xff0c;或将java对象转换为响应报文 ②HttpMessageConverter提供了两个注解和两个类型 RequestBody,ResponseBody,RequestEntity,ResponseEntity …

深入详解CFS任务放置代码

一、前言 本文出现的内核代码来自Linux5.10.61&#xff0c;为了减少篇幅&#xff0c;我们对引用的代码进行了删减&#xff08;例如去掉了NUMA的代码&#xff0c;毕竟手机平台上我们暂时不关注这个特性&#xff09;&#xff0c;如果有兴趣&#xff0c;读者可以配合完整的源代码…

Spring Boot JAVA 统一返回的信息

现在的项目是前后端开发的居多&#xff0c;那么&#xff0c;后端的开发只需要返回相关的接口就行了。那么&#xff0c;我们怎么定义接口返回的数据&#xff0c;怎么使用 Spring Boot 来统一处理返回的信息呢&#xff1f; 开发环境如下&#xff1a; IntelliJ IDEA 2021.2.2 (U…

linuxOPS基础_linux权限管理

权限概述 什么是权限 ​ 在多用户计算机系统的管理中&#xff0c;权限是指某个特定的用户具有特定的系统资源使用权利。 在Linux 中分别有读、写、执行权限 \权限针对文件权限针对目录读r(read)表示可以查看文件内容&#xff1b;cat、less…表示可以(ls)查看目录中存在的文…

无人机+ AI 图像分析:里斯本大学高效检测林业害虫

内容一览&#xff1a;早期发现虫害对于因地制宜采取防控措施至关重要。尽管遥感技术可用于快速扫描大面积区域&#xff0c;但面对低强度信号或难以检测的物体&#xff0c;其效果并不尽如人意。因此&#xff0c;里斯本大学研究人员将无人机与 AI 图像分析相结合&#xff0c;在此…

如何对自动化测试工具选型?这4个因素必须要拿捏好

测试开发工程师再做自动化时避免不了针对每个工具进行选型。今天就来看下工具选型的方法。 一&#xff1a;工具选型方法 在作为一名自动化测试开发工程师时&#xff0c;选择合适的 Web 自动化工具非常关键。以下是一些评估和选择工具的依据和方法&#xff1a; 1.支持的语言和…

接口测试介绍以及用例编写

6.1 接口 6.1.1 接口概述 定义&#xff1a; 接口就是API&#xff08;Application Programming Interface&#xff0c;应用程序接口&#xff09;&#xff0c;是一个软件或服务对外提供的接口&#xff0c;别人只要调用这接口&#xff0c;而内部如何实现&#xff0c;不需要关心。…

608教室使用方法

一、教室平面图 608教室的布局如下&#xff0c;重要的设备已经在图中标出。总开关、一体机和机柜。   二、使用方法 2.1 房间机器上电 进门后首先走到“总开关位置”&#xff0c;将电匝闭合。 原来的开关如图所示&#xff0c;有3组开关&#xff0c;1号组开关用于控制插座、…

突破办公瓶颈,推荐5款电脑办公软件

1.AnyTXT AnyTXT是一款搜文件内容的第三方全文搜索工具&#xff0c;速度极快&#xff0c;基本秒出结果。而且右边可以直接预览文件&#xff0c;筛选&#xff0c;复制&#xff0c;翻译等功能丰富&#xff0c;完美替代自带的搜索。 2.Groupy 这是用于快速切换窗口的小型精致工…