FreeRTOS入门--任务
目录
一、什么是任务
二、创建任务---xTaskCreate函数
三、任务的删除
四、任务优先级
1.阻塞状态(Blocked)
2.暂停状态(Suspended)
3.就绪状态(Ready)
五、Delay
六、调度算法
一、什么是任务
在FreeRTOS中,任务就是一个函数,原型如下:
void ATaskFunction( void *pvParameters );
要注意的是:
这个函数不能返回
同一个函数,可以用来创建多个任务;换句话说,多个任务可以运行同一个函数
函数内部,尽量使用局部变量:
每个任务都有自己的栈
每个任务运行这个函数时
任务A的局部变量放在任务A的栈里、任务B的局部变量放在任务B的栈里
不同任务的局部变量,有自己的副本
任务示例如下:
void ATaskFunction( void *pvParameters )
{
/* 对于不同的任务,局部变量放在任务的栈里,有各自的副本 */
int32_t lVariableExample = 0;
/* 任务函数通常实现为一个无限循环 */
for( ;; )
{
/* 任务的代码 */
}
/* 如果程序从循环中退出,一定要使用vTaskDelete删除自己
* NULL表示删除的是自己
*/
vTaskDelete( NULL );
/* 程序不会执行到这里, 如果执行到这里就出错了 */
}
二、创建任务---xTaskCreate函数
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, // 函数指针, 任务函数
const char * const pcName, // 任务的名字
const configSTACK_DEPTH_TYPE usStackDepth, // 栈大小,单位为word,10表示40字节
void * const pvParameters, // 调用任务函数时传入的参数
UBaseType_t uxPriority, // 优先级
TaskHandle_t * const pxCreatedTask ); // 任务句柄, 以后使用它来操作这个任务
参数描述:
pvTaskCode
函数指针,可以简单地认为任务就是一个C函数。
它稍微特殊一点:永远不退出,或者退出时要调用"vTaskDelete(NULL)"
pcName
任务的名字,FreeRTOS内部不使用它,仅仅起调试作用。
长度为:configMAX_TASK_NAME_LEN
usStackDepth
每个任务都有自己的栈,这里指定栈大小。
单位是word,比如传入100,表示栈大小为100 word,也就是400字节。
最大值为uint16_t的最大值。
怎么确定栈的大小,并不容易,很多时候是估计。
精确的办法是看反汇编码。
pvParameters
调用pvTaskCode函数指针时用到:pvTaskCode(pvParameters)
uxPriority
优先级范围:0~(configMAX_PRIORITIES – 1)
数值越小优先级越低,:更高优先级的、或者后面创建的任务先运行。
如果传入过大的值,xTaskCreate会把它调整为(configMAX_PRIORITIES – 1)
pxCreatedTask
用来保存xTaskCreate的输出结果:task handle。
以后如果想操作这个任务,比如修改它的优先级,就需要这个handle。
如果不想使用该handle,可以传入NULL。
返回值
成功:pdPASS;
失败:errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY(失败原因只有内存不足)
注意:返回值是pdFAIL不对。
pdFAIL是0,errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY是-1。
多个任务可以使用同一个函数;
void vTaskFunction( void *pvParameters )
{const char *pcTaskText = pvParameters;volatile uint32_t ul; /* volatile用来避免被优化掉 *//* 任务函数的主体一般都是无限循环 */for( ;; ){/* 打印任务的信息 */printf(pcTaskText);/* 延迟一会(比较简单粗暴) */for( ul = 0; ul < mainDELAY_LOOP_COUNT; ul++ ){}}
}
static const char *pcTextForTask1 = "T1 run\r\n";
static const char *pcTextForTask2 = "T2 run\r\n";
int main( void )
{prvSetupHardware();xTaskCreate(vTaskFunction, "Task 1", 1000, (void *)pcTextForTask1, 1, NULL);xTaskCreate(vTaskFunction, "Task 2", 1000, (void *)pcTextForTask2, 1, NULL);/* 启动调度器 */vTaskStartScheduler();/* 如果程序运行到了这里就表示出错了, 一般是内存不足 */return 0;
}
三、任务的删除
删除任务时使用的函数如下:
void vTaskDelete( TaskHandle_t xTaskToDelete );
pvTaskCode
任务句柄,使用xTaskCreate创建任务时可以得到一个句柄。
也可传入NULL,这表示删除自己。
自杀: vTaskDelete(NULL)
被杀:别的任务执行vTaskDelete(pvTaskCode) ,pvTaskCode是自己的句柄
杀人:执行vTaskDelete(pvTaskCode) ,pvTaskCode是别的任务的句柄
FreeRTOS一天一个小知识之任务延时函数vTaskDelay-CSDN博客
https://blog.csdn.net/simplemethane/article/details/116998825以下是这篇文章中谈到的延迟的内容:
Dealy的延时,是通过CPU做循环的方式来延时,CPU在延时中是做不了其他东西的,大大浪费了CPU的效率!而且非常危险!
所以大家在裸机中如果要需要很长时间延时的话,建议用定时器来延时。
void vTaskDelay( const TickType_t xTicksToDelay ){BaseType_t xAlreadyYielded = pdFALSE;/* A delay time of zero just forces a reschedule. */if( xTicksToDelay > ( TickType_t ) 0U ){configASSERT( uxSchedulerSuspended == 0 );vTaskSuspendAll();{traceTASK_DELAY();/* A task that is removed from the event list while the* scheduler is suspended will not get placed in the ready* list or removed from the blocked list until the scheduler* is resumed.** This task cannot be in an event list as it is the currently* executing task. */prvAddCurrentTaskToDelayedList( xTicksToDelay, pdFALSE );}xAlreadyYielded = xTaskResumeAll();}else{mtCOVERAGE_TEST_MARKER();}/* Force a reschedule if xTaskResumeAll has not already done so, we may* have put ourselves to sleep. */if( xAlreadyYielded == pdFALSE ){portYIELD_WITHIN_API();}else{mtCOVERAGE_TEST_MARKER();}}
FreeRTOS这个任务执行是这样的。首先TASK1创建,然后在创建TASK2
TASK先执行, 执行到GPIO_SetBits(GPIOC,GPIO_Pin_2); 下一句vTaskDelay(500); 延时500ms,其实就是任务挂起500ms,CPU此时不会执行TASK的任务,去执行处于就绪态的TASK2, 当TASK2的GPIO_ResetBits(GPIOC,GPIO_Pin_3); 执行好了之后执行下一条 vTaskDelay(200);此时TASK1延时500ms,TASK延时200ms。
这时候FreeRTOS是没有执行处于就绪态的任务的,只有执行空闲任务 。此时由于TASK2是延时200ms,比TASK2延时的500ms要快,所以TASK2比TASK1更早进入就绪态,此时CPU执行 GPIO_SetBits(GPIOC,GPIO_Pin_3); 这一语句,执行好了之后TASK2又延时800ms,进入挂起态。当TASK1延时500ms到,TASK1进入就绪态,
执行GPIO_ResetBits(GPIOC,GPIO_Pin_2); i++;语句,执行完之后,TASK1又进入500ms的延时,进入挂起态~
【
任务堆栈
任务堆栈用来保存任务现场(CPU寄存器值),创建任务的时候需要指定任务堆栈,任务堆栈的变量类型为StackType_t,再次运行任务时会从上次中断的地方开始运行
】
所以在FreeRTOS中的延时函数,只是任务挂起和任务恢复而已


//任务一
void vTask1( void *pvParameters )
{
const TickType_t xDelay100ms = pdMS_TO_TICKS( 100UL );
BaseType_t ret;
/* 任务函数的主体一般都是无限循环 */
for( ;; )
{
/* 打印任务的信息 */
printf("Task1 is running\r\n");
ret = xTaskCreate( vTask2, "Task 2", 1000, NULL, 2, &xTask2Handle );
if (ret != pdPASS)
printf("Create Task2 Failed\r\n");
// 如果不休眠的话, Idle任务无法得到执行
// Idel任务会清理任务2使用的内存
// 如果不休眠则Idle任务无法执行, 最后内存耗尽
vTaskDelay( xDelay100ms );
}//任务二
void vTask2( void *pvParameters )
{
/* 打印任务的信息 */
printf("Task2 is running and about to delete itself\r\n");
// 可以直接传入参数NULL, 这里只是为了演示函数用法
vTaskDelete(xTask2Handle);
}//main函数
int main( void )
{
prvSetupHardware();
xTaskCreate(vTask1, "Task 1", 1000, NULL, 1, NULL);
/* 启动调度器 */
vTaskStartScheduler();
/* 如果程序运行到了这里就表示出错了, 一般是内存不足 */
return 0;
}

main函数中创建任务1,优先级为1。任务1运行时,它创建任务2,任务2的优先级是2。
任务2的优先级最高,它马上执行。
任务2打印一句话后,就删除了自己。
任务2被删除后,任务1的优先级最高,轮到任务1继续运行,它调用vTaskDelay() 进入Block状
态
任务1 Block期间,轮到Idle任务执行:它释放任务2的内存(TCB、栈)
时间到后,任务1变为最高优先级的任务继续执行。
如此循环。
在任务1的函数中,如果不调用vTaskDelay,则Idle任务用于没有机会执行,它就无法释放创建任务2是分配的内存。而任务1在不断地创建任务,不断地消耗内存,最终内存耗尽再也无法创建新的任务。

四、任务优先级
高优先级的任务先运行。
优先级的取值范围是:0~(configMAX_PRIORITIES – 1),数值越大优先级越高。
FreeRTOS会确保最高优先级的、可运行的任务,马上就能执行
对于相同优先级的、可运行的任务,轮流执行
举例子:
厨房着火了,当然优先灭火
喂饭、回复信息同样重要,轮流做
对于同优先级的任务,它们“轮流”执行。怎么轮流?你执行一会,我执行一会。
"一会"怎么定义?
人有心跳,心跳间隔基本恒定。
FreeRTOS中也有心跳,它使用定时器产生固定间隔的中断。这叫Tick、滴答,比如每10ms发生一次时钟中断。
假设t1、t2、t3发生时钟中断
两次中断之间的时间被称为时间片(time slice、tick period)
时间片的长度由configTICK_RATE_HZ 决定,假设configTICK_RATE_HZ为100,那么时间片长度就是10ms

相同优先级的任务怎么切换呢?请看下图:
任务2从t1执行到t2
在t2发生tick中断,进入tick中断处理函数:
选择下一个要运行的任务
执行完中断处理函数后,切换到新的任务:任务1
任务1从t2执行到t3
从图中可以看出,任务运行的时间并不是严格从t1,t2,t3哪里开始

在FreeRTOS中,系统时钟节拍的特点就是周期性中断,既然要产生中断那就需要定时器,所以在这里就是使用了一个24位的定时器,采用向下计数的方式,然后可以产生周期性的中断。
系统在使用的时候,一般是在FreeRTOSConfig.h里面进行配置
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
这是一个常用的配置,系统的节拍频率设置为1000,也就是说系统的节拍周期为1ms,这也是最为典型的一种设置。
vTaskDelay(2); // 等待2个Tick,假设configTICK_RATE_HZ=100, Tick周期时10ms, 等待20ms
// 还可以使用pdMS_TO_TICKS宏把ms转换为tick
vTaskDelay(pdMS_TO_TICKS(100)); // 等待100ms
注意,基于Tick实现的延时并不精确,比如vTaskDelay(2) 的本意是延迟2个Tick周期,有可能经过1个Tick多一点就返回了。

使用vTaskDelay函数时,建议以ms为单位,使用pdMS_TO_TICKS把时间转换为Tick。
将毫秒数换算成了tick数
#define pdMS_TO_TICKS( xTimeInMs ) ( ( TickType_t ) ( ( ( TickType_t ) ( xTimeInMs ) * ( TickType_t ) configTICK_RATE_HZ ) / ( TickType_t ) 1000U ) )
SysTick 定时器被捆绑在 NVIC 中,用于产生 SysTick 异常(异常号: 15), 滴答定时器是一个 24 位的递减计数器,支持中断。
使用比较简单, 专门用于给操作系统提供时钟节拍。
FreeRTOS 的系统时钟节拍可以在配置文件 FreeRTOSConfig.h 里面设置:
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
如上所示的宏定义配置表示系统时钟节拍是 1KHz,即 1ms。
void vTask3( void *pvParameters )
{
const TickType_t xDelay3000ms = pdMS_TO_TICKS( 3000UL );
/* 任务函数的主体一般都是无限循环 */
for( ;; )
{
/* 打印任务的信息 */
printf("T3\r\n");
// 如果不休眠的话, 其他任务无法得到执行
vTaskDelay( xDelay3000ms );
}
}
修改优先级:
使用uxTaskPriorityGet来获得任务的优先级:
UBaseType_t uxTaskPriorityGet( const TaskHandle_t xTask );
使用参数xTask来指定任务,设置为NULL表示获取自己的优先级。
使用vTaskPrioritySet 来设置任务的优先级:
void vTaskPrioritySet( TaskHandle_t xTask,
UBaseType_t uxNewPriority );
使用参数xTask来指定任务,设置为NULL表示设置自己的优先级;
参数uxNewPriority表示新的优先级,取值范围是0~(configMAX_PRIORITIES – 1)。
五、任务状态
void vTask1( void *pvParameters )
{
/* 任务函数的主体一般都是无限循环 */
for( ;; )
{
/* 打印任务的信息 */
printf("T1\r\n");
}
}
void vTask2( void *pvParameters )
{
/* 任务函数的主体一般都是无限循环 */
for( ;; )
{
/* 打印任务的信息 */
printf("T2\r\n");
}
}
void vTask3( void *pvParameters )
{
const TickType_t xDelay3000ms = pdMS_TO_TICKS( 3000UL );
/* 任务函数的主体一般都是无限循环 */
for( ;; )
{
/* 打印任务的信息 */
printf("T3\r\n");
// 如果不休眠的话, 其他任务无法得到执行
vTaskDelay( xDelay3000ms );
}
}
/***********************************************/
//main函数:
int main()
{
prvSetupHardware();
xTaskCreate(vTask1, "Task 1", 1000, NULL, 1, NULL);
xTaskCreate(vTask2, "Task 2", 1000, NULL, 1, NULL);
xTaskCreate(vTask3, "Task 3", 1000, NULL, 2, NULL);
/* 启动调度器 */
vTaskStartScheduler();
/* 如果程序运行到了这里就表示出错了, 一般是内存不足 */
return 0;
}
如果把任务3中的vTaskDelay调用注释掉,那么任务1、任务2根本没有执行的机会,任务1、任务2被"饿死"了(starve)。

1.阻塞状态(Blocked)
在实际产品中,我们不会让一个任务一直运行,而是使用"事件驱动"的方法让它运行:任务要等待某个事件,事件发生后它才能运行在等待事件过程中,它不消耗CPU资源在等待事件的过程中,这个任务就处于阻塞状态(Blocked)
在阻塞状态的任务,它可以等待两种类型的事件:
时间相关的事件可以等待一段时间:我等2分钟也可以一直等待,直到某个绝对时间:我等到下午3点
同步事件:这事件由别的任务,或者是中断程序产生例子1:任务A等待任务B给它发送数据例子2:任务A等待用户按下按键
在等待一个同步事件时,可以加上超时时间。
比如等待队里数据,超时时间设为10ms:
10ms之内有数据到来:成功返回
10ms到了,还是没有数据:超时返回
2.暂停状态(Suspended)
在日常生活的例子中,母亲正在电脑前跟同事沟通,母亲可以暂停:
好烦啊,我暂停一会
领导说:你暂停一下
FreeRTOS中的任务也可以进入暂停状态,唯一的方法是通过vTaskSuspend函数。函数原型如下:
void vTaskSuspend( TaskHandle_t xTaskToSuspend );
参数xTaskToSuspend表示要暂停的任务,如果为NULL,表示暂停自己。
要退出暂停状态,只能由别人来操作:
别的任务调用:vTaskResume
中断程序调用:xTaskResumeFromISR
实际开发中,暂停状态用得不多。
3.就绪状态(Ready)
这个任务完全准备好了,随时可以运行:只是还轮不到它。这时,它就处于就绪态(Ready)。
五、Delay
有两个Delay函数:
vTaskDelay:至少等待指定个数的Tick Interrupt才能变为就绪状态
vTaskDelayUntil:等待到指定的绝对时刻,才能变为就绪态。
void vTaskDelay( const TickType_t xTicksToDelay ); /* xTicksToDelay: 等待多少给
Tick */
/* pxPreviousWakeTime: 上一次被唤醒的时间
* xTimeIncrement: 要阻塞到(pxPreviousWakeTime + xTimeIncrement)
* 单位都是Tick Count
*/
BaseType_t xTaskDelayUntil( TickType_t * const pxPreviousWakeTime,
const TickType_t xTimeIncrement );
使用vTaskDelay(n)时,进入、退出vTaskDelay的时间间隔至少是n个Tick中断
使用xTaskDelayUntil(&Pre, n)时,前后两次退出xTaskDelayUntil的时间至少是n个Tick中断退出xTaskDelayUntil时任务就进入的就绪状态,一般都能得到执行机会,所以可以使用xTaskDelayUntil来让任务周期性地运行

int main( void )
{
prvSetupHardware();
/* Task1的优先级更高, Task1先执行 */
xTaskCreate( vTask1, "Task 1", 1000, NULL, 2, NULL );
xTaskCreate( vTask2, "Task 2", 1000, NULL, 1, NULL );
/* 启动调度器 */
vTaskStartScheduler();
/* 如果程序运行到了这里就表示出错了, 一般是内存不足 */
return 0;
}
void vTask1( void *pvParameters )
{
const TickType_t xDelay50ms = pdMS_TO_TICKS( 50UL );
TickType_t xLastWakeTime;
int i;
/* 获得当前的Tick Count */
xLastWakeTime = xTaskGetTickCount();
for( ;; )
{
flag = 1;
/* 故意加入多个循环,让程序运行时间长一点 */
for (i = 0; i <5; i++)
printf( "Task 1 is running\r\n" );
##if 1
vTaskDelay(xDelay50ms);
##else
vTaskDelayUntil(&xLastWakeTime, xDelay50ms);
##endif
}
}
void vTask2( void *pvParameters )
{
for( ;; )
{
flag = 0;
printf( "Task 2 is running\r\n" );
}
}
使用Keil的逻辑分析观察flag变量的bit波形,如下:
flag为1时表示Task1在运行,flag为0时表示Task2在运行,也就是Task1处于阻塞状态
vTaskDelay:指定的是阻塞的时间
vTaskDelayUntil:指定的是任务执行的间隔、周期

六、调度算法
static volatile int flagIdleTaskrun = 0; // 空闲任务运行时flagIdleTaskrun=1
static volatile int flagTask1run = 0; // 任务1运行时flagTask1run=1
static volatile int flagTask2run = 0; // 任务2运行时flagTask2run=1
static volatile int flagTask3run = 0; // 任务3运行时flagTask3run=1
int main( void )
{
prvSetupHardware();
xTaskCreate(vTask1, "Task 1", 1000, NULL, 0, NULL);
xTaskCreate(vTask2, "Task 2", 1000, NULL, 0, NULL);
xTaskCreate(vTask3, "Task 3", 1000, NULL, 2, NULL);
/* 启动调度器 */
vTaskStartScheduler();
/* 如果程序运行到了这里就表示出错了, 一般是内存不足 */
return 0;
}
void vTask1( void *pvParameters )
{
/* 任务函数的主体一般都是无限循环 */for( ;; ){flagIdleTaskrun = 0;flagTask1run = 1;flagTask2run = 0;flagTask3run = 0;/* 打印任务的信息 */printf("T1\r\n");}
}
void vTask2( void *pvParameters )
{
/* 任务函数的主体一般都是无限循环 */for( ;; ){flagIdleTaskrun = 0;flagTask1run = 0;flagTask2run = 1;flagTask3run = 0;/* 打印任务的信息 */printf("T2\r\n");}
}
void vTask3( void *pvParameters )
{const TickType_t xDelay5ms = pdMS_TO_TICKS( 5UL );/* 任务函数的主体一般都是无限循环 */for( ;; ){flagIdleTaskrun = 0;flagTask1run = 0;flagTask2run = 0;flagTask3run = 1;/* 打印任务的信息 */printf("T3\r\n");// 如果不休眠的话, 其他任务无法得到执行vTaskDelay( xDelay5ms );}
}
提供了一个空闲任务的钩子函数:
void vApplicationIdleHook(void)
{flagIdleTaskrun = 1;flagTask1run = 0;flagTask2run = 0;flagTask3run = 0;/* 故意加入打印让flagIdleTaskrun变为1的时间维持长一点 */printf("Id\r\n");
}
抢占时:高优先级任务就绪时,就可以马上执行
不抢占时:优先级失去意义了,既然不能抢占就只能协商了,图中任务1一直在运行(一点都没有协商精神),其他任务都无法执行。即使任务3的vTaskDelay 已经超时、即使它的优先级更高,都没办法执行。


相关文章:
FreeRTOS入门--任务
目录 一、什么是任务 二、创建任务---xTaskCreate函数 三、任务的删除 四、任务优先级 1.阻塞状态(Blocked) 2.暂停状态(Suspended) 3.就绪状态(Ready) 五、Delay 六、调度算法 一、什么是任务 在FreeRTOS中,任务就是一个函数,原型如下ÿ…...
4个解决特定的任务的Pandas高效代码
在本文中,我将分享4个在一行代码中完成的Pandas操作。这些操作可以有效地解决特定的任务,并以一种好的方式给出结果。 从列表中创建字典 我有一份商品清单,我想看看它们的分布情况。更具体地说:希望得到唯一值以及它们在列表中出…...
【已解决】AttributeError: module ‘gradio‘ has no attribute ‘Image‘
问题描述 AttributeError: module gradio has no attribute Image 不知道作者用的是哪个gradio版本,最新的版本报错AttributeError: module gradio has no attribute outputs , 换一个老一点的版本会报错AttributeError: module gradio has no attribute…...
高级软件工程15本书籍
如果您想学习软件工程技能并提高您的专业知识,那么这里是您的最佳选择。我们有一本很棒的书,可以极大地增强您在软件工程方面的知识。 1)干净的代码 Robert C. Martin 写了一本名为“干净代码:敏捷软件工艺手册”的书。在本书中&…...
计网Lesson3 - 计算机网络评价指标与封包解包
文章目录 计算机网络的性能指标1. 速率2. 带宽3. 吞吐量4. 时延5. 时延带宽积6. 往返时间7. 利用率8. 数据的解包和封包 计算机网络的术语实体协议服务 计算机网络的性能指标 1. 速率 数据…...
深度学习好文记录,反复学习
recent update time:2023.12.2 深度学习入门 - 知乎、这本书也很好,作者写的专栏不错。 机器学习,深度学习一些好文_一只菜得不行的鸟的博客-CSDN博客 卷积神经网络学习路线(五)| 卷积神经网络参数设置,提…...
CSS浅谈动画性能
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 目的一、举个栗子二、性能分析1.从图层分析2.性能分析 总结 目的 为了探究使用动画时,『transform』和『width、height、margin等』的差异 一、举个栗子…...
万能的视频格式播放器
今天博主给大家带来一款“万能”的视频播放器——VLC Media Player,支持的文件格式非常多,大家快来一起看看吧! VLC Media Player 是一款可播放大多数格式,而无需安装编解码器包的媒体播放器。可以播放 MPEG-1、MPEG-2、MPEG-4、D…...
设计模式---第五篇
系列文章目录 文章目录 系列文章目录前言一、知道观察者模式吗?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 一、知道观察者模式吗? 答:观察者模式是定义对…...
.NET8构建统计Extreme Optimization Numerical Libraries
为 .NET 8 构建统计应用程序 Extreme Optimization Numerical Libraries for .NET V8.1.22 添加了对 .NET 8 的支持,使您可以使用最新版本的 Microsoft 平台。 Extreme Optimization Numerical Libraries for .NET 是通用数学和统计类的集合,为技术和统计…...
07-原型模式-C语言实现
原型模式: Specify the kinds of objects to create using a prototypical instance,and create new objects by copying this prototype.(用原型实例指定创建对象的种类, 并且通过拷贝这些原型创建新的对象。 ) UML图࿱…...
深度学习与深度迁移学习有什么区别?
深度学习包含深度迁移学习,它们都利用了深层神经网络(Deep Neural Network,DNN)来处理数据,并从中学习特征。但是,它们也有一些区别。 深度学习是一种机器学习方法,它通过多层神经网络来自动学…...
创建Asp.net MVC项目Ajax实现视图页面数据与后端Json传值显示
简述回顾 继上篇文章创建的mvc传值这里说明一下Json传值。在mvc框架中,不可避免地会遇到前台传值到后台,前台接收后台的值的情况(前台指view,后台指controller),有时只需要从控制器中返回一个处理的结果&a…...
1089 Insert or Merge (插入排序,相邻归并排序,附模拟实现)
注意点1:判断插入排序不能从头开始判断是否为目标数组, 比如:初始为1 2 3 4 3,目标数组也为1 2 3 4 3,则如果是从头开始推的,则下一步会变成1 2 3 4 3,而下一步应该是 1 2 3 3 4。所以我们应该…...
基于算能的国产AI边缘计算盒子8核心A53丨17.6Tops算力
边缘计算盒子 8核心A53丨17.6Tops算力 ● 可提供17.6TOPS(INT8)的峰值计算能力、2.2TFLOPS(FP32)的高精度算力,单芯片最高支持32路H.264 & H.265的实时解码能力。 ● 适配Caffe/TensorFlow/MxNet/PyTorch/ ONNX/…...
Eaxyx 让圆球跟随鼠标移动
如果出现2023,代表配置成功: 进入Eaxy官方网站,点击文档: 选择 函数->绘图函数->initgraph: 可以看见initgraph()函数有如下三个参数: 现在我们想生成一个1280*720大小的窗口: 我们需写如下代码: 但…...
Node.js 事件循环:定时任务、延迟任务和 I/O 事件的艺术
🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云…...
陪诊系统:基于自然语言处理的患者沟通创新
医疗领域的数字化转型正日益引入创新技术,其中基于自然语言处理(NLP)的陪诊系统成为提升患者沟通的一项关键技术。本文将深入研究这一领域,介绍陪诊系统如何借助NLP实现患者沟通的创新,并提供一个简单的Python代码示例…...
实用攻略——SD-WAN网络配置步骤详解
SD-WAN(软件定义广域网)作为一种新兴的网络技术,被广泛应用于构建高效、可靠的企业组网。 本文将详细介绍企业组网中SD-WAN涉及的配置过程,并提供一些配置技巧,以帮助企业快速了解企业组网的配置。通过使用SD-WAN技术&…...
无人机摄影测量
无人机摄影测量技术是传统航空摄影测量手段的有力补充,具有机动灵活、高效快速、精细准确、作业成本低、生产周期短、影像获取空间分辨率高、高危地区探测等优势。无人机与航空摄影测量相结合使得“无人机数字低空遥感”成为航空遥感领域的一个崭新发展方向。无人机…...
CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...
剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...
Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...
C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...
短视频矩阵系统文案创作功能开发实践,定制化开发
在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...
基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...
