当前位置: 首页 > news >正文

linux 基础知识点之工作队列workqueue

        多年前就了解了workqueue着玩意,但理解上就并不是很很深刻,今天重新梳理一下,本文重点的是哪个些现成的demo代码,都是可以直接拿来用的,这就是写这文章的目的和作用,就是为了备份后续工作用到的时候,可以快速Ctrl+c and Ctrl + v,接下来复制些前辈写好的理解概念,再结合一下个所整理得demo。

一、workqueue工作队列简介

        工作队列是除软中断和tasklet以外最常用的一种下半部机制,其基本原理是:把work(需要推迟执行的函数)交由一个内核线程来执行,工作队列总是在进程上下文执行。                               工作队列 ( workqueue )是将操作(或回调)延期异步执行的一种机制。工作队列可以把工作推后,交由一个内核线程去执行,并且工作队列是执行在线程上下文中,因此工作执行过程中可以被重新调度、抢占、睡眠。

​ 工作队列的优点:

    因工作队列在进程下文中执行,因此工作队列允许重新调度和睡眠,是异步执行的进程上下文。
    解决了如果软中断和tasklet执行时间过长会导致系统实时性下降等问题。

(1-1)work_struct工作

在 Linux 内核中,work_struct 是工作队列(workqueue)机制的核心数据结构,用于表示一个工作项。工作队列允许内核将任务推迟到其他线程中执行,这在处理中断或其他需要快速响应的场景中非常有用

struct my_work {struct work_struct work;int data;
};定义一个包含 work_struct 的结构体,用于存储工作项的数据

linux内核中使用work_struct结构体来表示一个工作,如下定义(/inlcude/linux/workqueue.h):

struct work_struct {atomic_long_t data;struct list_head entry;work_func_t func;
#ifdef CONFIG_LOCKDEPstruct lockdep_map lockdep_map;
#endif
};

(1-2)workqueue工作队列

把工作(包括该工作任务的执行回调函数)添加到一个队列,称为workqueue,即工作队列,然后通过worker-pool中的内核工作线程(worker)去执行这个回调函数。工作队列使用workqueue_struct结构体来表示,定义如下(/kernel/workqueue.c):

    创建工作队列:my_workqueue = create_workqueue("my_workqueue");使用 create_workqueue 创建一个工作队列,名称为 "my_workqueue"


(1-3)worker工作者线程

​ linux 内核使用工作者线程(worker thread)来处理工作队列中的各个工作,linux 内核使用
worker 结构体表示工作者线程,worker 结构体定义如下(/kernel/workqueue_internal.h)
  
二、workqueue工作队列的使用

​ 每一个worker工作线程中都有一个工作队列,工作线程处理自己工作队列中的所有工作。

在实际开发中,推荐使用默认的workqueue·工作队列,而不是新创建workqueue。使用方法如下:

​ 直接定义一个work_struct结构体变量,然后使用INIT_WORK宏来完成初始化工作,INIT_WORK定义如下:

#define INIT_WORK(_work, _func)

_work表示要初始化的工作,_func是工作对应的处理函数。

也可以使用 DECLARE_WORK 宏一次性完成工作的创建和初始化,宏定义如下:

#define DECLARE_WORK(n, f)

​ n 表示定义的工作(work_struct),f 表示工作对应的处理函数。和 tasklet 一样,工作也是需要调度才能运行的,工作的调度函数为schedule_work(),函数原型如下所示:

bool schedule_work(struct work_struct *work) //其实你就理解为工作队列启动回调的函数

使用cancel_work_sync()取消一个工作,函数原型如下所示:

bool cancel_work_sync(struct work_struct *work)

当然也可以自己创建一个workqueue,特别是网络子系统、块设备子系统情况下等。具体步骤如下:

    使用alloc_workqueue()创建新的workqueue。
    使用INIT_WORK()宏声明一个work和该work的回调函数。
    使用queue_work()在新的workqueue上调度一个work //其实就理解为工作队列启动回调的函数
    使用flush_workqueue()去flush 工作队列上的所有work。

来个demo:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/time.h>#include <linux/jiffies.h>
#include <linux/workqueue.h>
#include <linux/slab.h> //kmalloc kfree#include <linux/sched.h>
#include <linux/delay.h>#define WAIT_TIMES 5000static char data[] = "[Tab] test for demo work";struct work_ctx{struct work_struct real_work;char *str;int arg;
}work_ctx;struct work_ctx *demo_work;// 定义工作队列
static struct workqueue_struct *my_workqueue;static void demo_work_func(struct work_struct *work){struct work_ctx *temp_work = container_of(work,struct work_ctx,real_work);printk(KERN_INFO "[work]=> PID: %d; NAME: %s\n", current->pid, current->comm);printk(KERN_INFO "[work]=> sleep 1 seconds\n");set_current_state(TASK_INTERRUPTIBLE);schedule_timeout(1 * HZ); //Wait 1 secondsprintk(KERN_INFO "[work]=> data is: %d  %s\n", temp_work->arg,temp_work->str);
}static int __init demo_thread_init(void){int count = 10;// 创建工作队列my_workqueue = create_workqueue("my_workqueue");if (!my_workqueue) {return -ENOMEM;}    demo_work = kmalloc(sizeof(*demo_work),GFP_KERNEL);	INIT_WORK(&demo_work->real_work, demo_work_func);demo_work->str = data;while(count--){//msleep(5000);msleep(WAIT_TIMES);//mdelay(WAIT_TIMES);demo_work->arg = count;//schedule_work(&demo_work->real_work);// 提交工作项到工作队列//queue_work(my_workqueue, &my_work->work);        queue_work(my_workqueue, &demo_work->real_work);}return 0;
}module_init(demo_thread_init);static void __exit demo_thread_exit(void){flush_work(&demo_work->real_work);kfree(demo_work);
}
module_exit(demo_thread_exit);MODULE_LICENSE("GPL");	

除此之外,linux内核还提供了一个workqueue机制与timer机制相结合的延时机制—delayed_work。
Talk is cheap,show me the code

结合hrtimer_demo升级了一下:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/hrtimer.h>
#include <linux/ktime.h>#include <linux/time.h>#include <linux/jiffies.h>
#include <linux/workqueue.h>
#include <linux/slab.h> //kmalloc kfree#include <linux/sched.h>
#include <linux/delay.h>static struct hrtimer my_timer;
static int count = 0;#define WAIT_TIMES 5000static char data[] = "[Tab] test for demo work";struct work_ctx{struct work_struct real_work;char *str;int arg;
}work_ctx;struct work_ctx *demo_work;// 定义工作队列
static struct workqueue_struct *my_workqueue;static void demo_work_func(struct work_struct *work){struct work_ctx *temp_work = container_of(work,struct work_ctx,real_work);printk(KERN_INFO "[work]=> PID: %d; NAME: %s\n", current->pid, current->comm);printk(KERN_INFO "[work]=> sleep 1 seconds\n");set_current_state(TASK_INTERRUPTIBLE);schedule_timeout(1 * HZ); //Wait 1 secondsprintk(KERN_INFO "[work]=> data is: %d  %s\n", temp_work->arg,temp_work->str);
}#if 1
enum hrtimer_restart my_timer_callback(struct hrtimer *timer)
{count++;//pr_info("Timer expired! Count: %d\n", count);printk("enter [%s] line = %d, count = %d. \n", __func__, __LINE__, count);demo_work->arg = count;schedule_work(&demo_work->real_work);// 提交工作项到工作队列   //queue_work(my_workqueue, &demo_work->real_work); // 重新启动定时器,设置下次到期时间为 1 秒hrtimer_forward_now(timer, ms_to_ktime(2000));//调整高分辨率定时器(high-resolution timer,hrtimer)到期时间的一个函数return HRTIMER_RESTART; // 代表重复定时器 //重启方式
}
#elseenum hrtimer_restart my_timer_callback(struct hrtimer *timer)
{count++;//pr_info("Timer expired! Count: %d\n", count);printk("enter [%s] line = %d, count = %d. \n", __func__, __LINE__, count);// 重新启动定时器,设置下次到期时间为 1 秒hrtimer_forward_now(timer, ms_to_ktime(2000));//调整高分辨率定时器(high-resolution timer,hrtimer)到期时间的一个函数return HRTIMER_RESTART; // 代表重复定时器 //重启方式
}enum hrtimer_restart my_timer_callback(struct hrtimer *timer)
{pr_info(KERN_INFO "High-resolution timer expired after 1 second\n");printk("enter [%s] line = %d, count = %d. \n", __func__, __LINE__, count);return HRTIMER_NORESTART; // 代表不重复定时器
}
#endifstatic int __init my_module_init(void)
{ktime_t ktime;printk("enter [%s] line = %d \n", __func__, __LINE__);pr_info("High-Resolution Timer Example Module Loaded\n");// 创建工作队列my_workqueue = create_workqueue("my_workqueue");if (!my_workqueue) {return -ENOMEM;}    demo_work = kmalloc(sizeof(*demo_work),GFP_KERNEL);	INIT_WORK(&demo_work->real_work, demo_work_func);demo_work->str = data;// 设置定时器初始时间为 1 秒ktime = ktime_set(10, 0); // 1 秒, 0 纳秒hrtimer_init(&my_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);//初始化高分辨率定时器的函数my_timer.function = my_timer_callback;// 定时到期时的回调函数hrtimer_start(&my_timer, ktime, HRTIMER_MODE_REL);//启动高分辨率定时器的函数return 0;
}static void __exit my_module_exit(void)
{// 停止定时器hrtimer_cancel(&my_timer);pr_info("High-Resolution Timer Example Module Unloaded\n");
}module_init(my_module_init);
module_exit(my_module_exit);MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("High-Resolution Timer Example");
MODULE_AUTHOR("Pan Shuai");


                        原文链接:https://blog.csdn.net/iriczhao/article/details/122870227

 

Linux内核中的工作队列包括:共享工作队列和自定义工作队列。区别如下:

    1)共享工作队列:将新创建的工作任务添加到Linux内核创建的全局工作队列system_wq中,无需自己创建工作队列;

    2)自定义工作队列:将新创建的工作任务添加到自己创建的工作队列中;

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/kobject.h>
#include <linux/list.h>
#include <linux/kthread.h>
#include <asm/ptrace.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/interrupt.h>int data  = 10;static struct work_struct       work1;
static struct work_struct       work2;static void do_work1(struct work_struct *arg)
{printk(KERN_INFO "do_work1 .....");
}static void do_work2(struct work_struct *arg)
{printk(KERN_INFO "do_work2 .....");
}int threadfn(void *data)
{static int count =  0 ;int args = *(int *)data;printk(KERN_INFO "enter thead_fn");while(1){msleep(2*1000);printk(KERN_INFO "threadfn data: %d, count: %d",args , ++count);schedule_work(&work1);schedule_work(&work2);}
} static int __init test_kobj_init(void)
{INIT_WORK(&work1,do_work1);INIT_WORK(&work2,do_work2);struct task_struct *  thread =  kthread_create( threadfn,(void * )&data,"mythread");if(thread != NULL){printk(KERN_INFO "thread create success");wake_up_process(thread);}else{printk(KERN_ERR "thread create err");}return 0;
}static void __exit test_kobj_exit(void)
{printk(KERN_INFO "test_kobj_exit ");return;
}module_init(test_kobj_init);
module_exit(test_kobj_exit);MODULE_AUTHOR("copy other auther");
MODULE_LICENSE("GPL");

2、自定义工作队列举例(demol来源于网络)

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/kobject.h>
#include <linux/list.h>
#include <linux/kthread.h>
#include <asm/ptrace.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
int data  = 10;static struct workqueue_struct *workqueue;
static struct work_struct       work1;
static struct work_struct       work2;static void do_work1(struct work_struct *arg)
{printk(KERN_INFO "do_work1 .....");
}static void do_work2(struct work_struct *arg)
{printk(KERN_INFO "do_work2 .....");
}int threadfn(void *data)
{static int count =  0 ;int args = *(int *)data;printk(KERN_INFO "enter thead_fn");while(1){msleep(2*1000);printk(KERN_INFO "threadfn data: %d, count: %d",args , ++count);queue_work(workqueue,&work1);//将任务放到自己创建的工作队列上去执行queue_work(workqueue,&work2);}
} static int __init test_kobj_init(void)
{workqueue = create_workqueue("create_new_work_queue");INIT_WORK(&work1,do_work1);INIT_WORK(&work2,do_work2);struct task_struct *  thread =  kthread_create( threadfn,(void * )&data,"mythread");if(thread != NULL){printk(KERN_INFO "thread create success");wake_up_process(thread);}else{printk(KERN_ERR "thread create err");}return 0;
}static void __exit test_kobj_exit(void)
{printk(KERN_INFO "test_kobj_exit ");destroy_workqueue(workqueue);return;
}module_init(test_kobj_init);
module_exit(test_kobj_exit);MODULE_AUTHOR("copy other auther");
MODULE_LICENSE("GPL");

在使用如下函数时注意事项


    1、flush_work():堵塞工作任务,直到工作任务完成

    2、flush_delayed_work():等待延时工作任务完成

    3、cancel_work_sync():取消工作任务并等待它完成

    4、cancel_delayed_work():取消延时工作任务

    5、cancel_delayed_work_sync():取消延时工作任务并等待它完成

    6、create_workqueue():对于多CPU系统,内核会在每个CPU上创建一个工作队列,使线程处理并行化

    7、create_singlethread_workqueue():内核只在一个CPU上创建一个工作队列

    8、queue_work_on():在指定CPU上添加工作任务,queue_work()调用queue_work_on()在所有CPU上添加工作任务

常见的应用场景:


work_struct 是 Linux 内核中用于处理异步任务的机制,它允许内核将任务推迟到工作队列中,由工作线程在适当的时候执行。work_struct 可以处理多种类型的任务,以下是一些常见的应用场景:
1. 中断处理
中断处理程序需要快速完成,以避免过长时间占用 CPU。如果中断处理程序需要执行一些耗时的操作,可以将这些操作推迟到工作队列中执行。例如:

static void my_interrupt_handler(int irq, void *dev_id) {struct work_struct *work = (struct work_struct *)dev_id;queue_work(my_workqueue, work);
}

2. 定时任务
如果需要在特定时间后执行某些任务,可以使用 queue_delayed_work 将任务推迟到工作队列中。例如:

static void my_delayed_work_handler(struct work_struct *work) {printk(KERN_INFO "Delayed work handler called\n");
}static int __init my_module_init(void) {my_workqueue = create_workqueue("my_workqueue");if (!my_workqueue) {return -ENOMEM;}struct my_work *my_work = kmalloc(sizeof(struct my_work), GFP_KERNEL);if (!my_work) {return -ENOMEM;}INIT_DELAYED_WORK(&my_work->work, my_delayed_work_handler);queue_delayed_work(my_workqueue, &my_work->work, msecs_to_jiffies(1000)); // 延迟 1 秒return 0;
}


3. 文件系统操作
在文件系统操作中,某些耗时的操作可以推迟到工作队列中执行。例如,文件系统的同步操作可以使用工作队列来处理:


static void my_sync_handler(struct work_struct *work) {printk(KERN_INFO "File system sync handler called\n");// 执行文件系统同步操作
}static int __init my_module_init(void) {my_workqueue = create_workqueue("my_workqueue");if (!my_workqueue) {return -ENOMEM;}struct my_work *my_work = kmalloc(sizeof(struct my_work), GFP_KERNEL);if (!my_work) {return -ENOMEM;}INIT_WORK(&my_work->work, my_sync_handler);queue_work(my_workqueue, &my_work->work);return 0;
}

4. 设备驱动程序
在设备驱动程序中,某些操作(如硬件初始化、数据传输等)可以推迟到工作队列中执行。例如:

static void my_device_init_handler(struct work_struct *work) {printk(KERN_INFO "Device initialization handler called\n");// 执行设备初始化操作
}static int __init my_module_init(void) {my_workqueue = create_workqueue("my_workqueue");if (!my_workqueue) {return -ENOMEM;}struct my_work *my_work = kmalloc(sizeof(struct my_work), GFP_KERNEL);if (!my_work) {return -ENOMEM;}INIT_WORK(&my_work->work, my_device_init_handler);queue_work(my_workqueue, &my_work->work);return 0;
}

5. 网络协议栈
在网络协议栈中,某些操作(如数据包处理、连接管理等)可以推迟到工作队列中执行。例如:

static void my_packet_handler(struct work_struct *work) {printk(KERN_INFO "Packet handler called\n");// 处理数据包
}static int __init my_module_init(void) {my_workqueue = create_workqueue("my_workqueue");if (!my_workqueue) {return -ENOMEM;}struct my_work *my_work = kmalloc(sizeof(struct my_work), GFP_KERNEL);if (!my_work) {return -ENOMEM;}INIT_WORK(&my_work->work, my_packet_handler);queue_work(my_workqueue, &my_work->work);return 0;
}

6. 用户空间请求
在处理用户空间请求时,某些操作可以推迟到工作队列中执行。例如:

static void my_user_request_handler(struct work_struct *work) {printk(KERN_INFO "User request handler called\n");// 处理用户请求
}static int __init my_module_init(void) {my_workqueue = create_workqueue("my_workqueue");if (!my_workqueue) {return -ENOMEM;}struct my_work *my_work = kmalloc(sizeof(struct my_work), GFP_KERNEL);if (!my_work) {return -ENOMEM;}INIT_WORK(&my_work->work, my_user_request_handler);queue_work(my_workqueue, &my_work->work);return 0;
}

注意事项

    工作函数的执行环境:工作函数在工作线程中执行,允许睡眠,因此可以执行耗时操作。
    工作队列的销毁:在模块退出时,确保使用 flush_workqueue 等待所有工作完成,然后使用 destroy_workqueue 销毁工作队列。
    工作项的释放:在工作函数中,确保释放分配的工作项,避免内存泄漏。

通过这些示例,你可以看到 work_struct 可以处理多种类型的任务,包括中断处理、定时任务、文件系统操作、设备驱动程序、网络协议栈和用户空间请求等。这使得 work_struct 成为内核中处理异步任务的强大工具。

相关文章:

linux 基础知识点之工作队列workqueue

多年前就了解了workqueue着玩意&#xff0c;但理解上就并不是很很深刻&#xff0c;今天重新梳理一下&#xff0c;本文重点的是哪个些现成的demo代码&#xff0c;都是可以直接拿来用的&#xff0c;这就是写这文章的目的和作用&#xff0c;就是为了备份后续工作用到的时候&#x…...

C++蓝桥杯基础篇(二)

片头 嗨&#xff01;小伙伴们&#xff0c;今天我们将学习C蓝桥杯基础篇&#xff08;二&#xff09;&#xff0c;继续练习相关习题&#xff0c;准备好了吗&#xff1f;咱们开始咯~ 第1题 简单计算器输入两个数&#xff0c;以及一个运算符 &#xff0c;-&#xff0c;*&#xff…...

【Android—OpenCV实战】实现霍夫圆检测针对沙盘交通灯信号检测

文章目录 Android OpenCV实战&#xff1a;霍夫圆检测实现沙盘交通灯智能识别&#x1f31f; 引言&#xff1a;当计算机视觉遇见智慧交通&#x1f50d; 霍夫圆检测原理剖析&#x1f50d; 数学之美&#xff1a;参数空间转换&#x1f50d; 关键参数解析 &#x1f6e0; Android实现全…...

WPS如何接入DeepSeek(通过JS宏调用)

WPS如何接入DeepSeek 一、文本扩写二、校对三、翻译 本文介绍如何通过 WPS JS宏调用 DeepSeek 大模型&#xff0c;实现自动化文本扩写、校对和翻译等功能。 一、文本扩写 1、随便打开一个word文档&#xff0c;点击工具栏“工具”。 2、点击“开发工具”。 3、点击“查看代码”…...

图论——环检测

环检测以及拓扑排序 前言复习模版环检测-DFS版本环检测- BFS版本 前言 我觉得学习这些之前,一定要对图的数据结构和抽象模型有概念,并且图构建的代码模版应该手到擒来,不然还是挺折磨的,不是这差一点就是那差一点,写道力扣卡卡的非常烦人. 复习模版 我觉得单拿出来再说这个模…...

Chapter2:C#基本数据类型

参考书籍&#xff1a;《C#边做边学》&#xff1b; 2.C#基本数据类型 2.1 变量与常量 变量是程序运行过程中用于存放数据的存储单元&#xff0c;变量的值的程序运行过程中可以改变&#xff1b; 变量定义&#xff1a; 定义变量时&#xff0c;必须给每个变量起名&#xff0c;通过…...

kafka服务端之控制器

文章目录 概述控制器的选举与故障恢复控制器的选举故障恢复 优雅关闭分区leader的选举 概述 在Kafka集群中会有一个或多个broker&#xff0c;其中有一个broker会被选举为控制器&#xff08;Kafka Controler&#xff09;&#xff0c;它负责管理整个集群中所有分区和副本的状态。…...

Unity笔试常考

线程同步的几种方式 1.信号量pv操作 2.互斥加锁 3.条件变量 五层网络协议指的是哪五层 1.应用层 2.运输层 3.网络层 4.链路层 5.物理层 TCP和UDP区别 tcp 面向连接&#xff0c;保证发送顺序&#xff0c;速度慢&#xff0c;必须在线&#xff0c;三次握手&#xff0c;4次挥手…...

移植BOA服务器到GEC2440开发板

所需软件:boa-0.94.13.tar.tar(下载:http://www.boa.org/boa-0.94.13.tar.gz) 步骤: 设置好交叉编译工具链。 1、解压下载好的压缩包(tar xzvf boa-0.94.13.tar.tar),并进入解压后的目录(cd boa-0.94.13),再进行如下操作: 先进入到src目录(下面操作都是在该目录下进行…...

WPS如何接入DeepSeek(通过第三方工具)

WPS如何接入DeepSeek 一、下载并安装OfficeAI插件二、配置OfficeAI插件三、使用DeepSeek功能 本文介绍如何通过 WPS 的第三方工具调用 DeepSeek 大模型&#xff0c;实现自动化文本扩写、校对和翻译等功能。 一、下载并安装OfficeAI插件 1、访问OfficeAI插件下载地址&#xff…...

【安当产品应用案例100集】037-强化OpenVPN安全防线的卓越之选——安当ASP身份认证系统

在当前数字化时代&#xff0c;网络安全已成为企业发展的重要组成部分。对于使用OpenVPN的企业而言&#xff0c;确保远程访问的安全性尤为重要。安当ASP身份认证系统凭借其强大的功能和便捷的集成方式&#xff0c;为OpenVPN的二次登录认证提供了理想的解决方案&#xff0c;特别是…...

Windows Docker笔记-制作、加载镜像

引言 在文章《Windows Docker笔记-在容器中运行项目》中&#xff0c;已经在容器中运行了项目。而且在这个容器中&#xff0c;已经调试好了项目运行的环境。 使用docker&#xff0c;就是为了在项目发布到生产环境时&#xff0c;不用再去安装项目运行的环境&#xff0c;直接丢给…...

leetcode_26删除有序数组中的重复项

1. 题意 给定一个重复数组&#xff0c;删除其中的重复项目。 2. 题解 双指针 一个指针指向有序不重复数组的最后一个数&#xff0c;另外一个数遍历整个数组&#xff0c;若两个指针对应用的数不相同&#xff0c;有序数组的指针右移&#xff0c;将数填入。 代码一 class Sol…...

速递丨DeepSeek刚刚成立香港子公司,或因考虑香港上市和招募全球AI人才

图片来源&#xff1a;DeepSeek 根据彭博社和财联社报道&#xff0c;DeepSeek 2月5日在香港成立了两家公司——DeepSeek Limited 和 DeepSeek (HK) Limited。 香港中文大学莊太量教授表示&#xff0c;DeepSeek进军香港将推动该市的金融科技发展。如果DeepSeek考虑在香港上市&a…...

笔灵ai写作技术浅析(六):智能改写与续写

笔灵AI写作中的智能改写和续写技术是其核心功能之一,旨在帮助用户生成高质量、多样化的文本内容。 一、智能改写技术 1. 基本原理 智能改写的目标是在保持原文语义不变的前提下,对文本进行重新表述,生成语法正确、语义连贯且风格多样的新文本。其核心思想是通过语义理解和…...

【在线优化】【有源程序】基于遗传算法(GA)和粒子群优化(PSO)算法的MPPT控制策略

目录 一、背景 二、源程序及结果 2.1 simulink仿真程序 2.2 GA模块源程序 2.3 PSO模块源程序 三、程序运行结果 3.1 基于GA优化的MPPT 3.2 基于PSO优化的MPPT 一、背景 MPPT策略能够显著提高光伏、风电等发电效率&#xff0c;节省大量成本。该策略的经典算法是&#xf…...

使用 Three.js 实现热力渐变效果

大家好&#xff01;我是 [数擎 AI]&#xff0c;一位热爱探索新技术的前端开发者&#xff0c;在这里分享前端和 Web3D、AI 技术的干货与实战经验。如果你对技术有热情&#xff0c;欢迎关注我的文章&#xff0c;我们一起成长、进步&#xff01; 开发领域&#xff1a;前端开发 | A…...

java-异常家族梳理(流程图)

前言: 使用流程图梳理异常,便于理解 梳理: Throwable ├── Error(严重错误,无需捕获) │ ├── OutOfMemoryError │ ├── StackOverflowError │ └── ... ├── Exception(可捕获处理) │ ├── RuntimeException(非检查异常/Unchecked) │ …...

开启蓝耘之旅:DeepSeek R1 模型在智算平台的起步教程

----------------------------------------------------------我的个人主页-------------------- 动动你的手指----------------------------------------点赞&#x1f44d; 收藏❤--------------------------------------------------------------- 引言 在深度学习的广袤领…...

[高等数学]不定积分的概念与性质

一、知识点 &#xff08;一&#xff09;原函数与不定积分的概念 定义1&#xff08;原函数&#xff09; 如果在区间 I I I 上&#xff0c;可导函数 F ( x ) F(x) F(x) 的导函数为 f ( x ) f(x) f(x)&#xff0c;即对任一 x ∈ I x\in I x∈I&#xff0c;都有 F ′ ( x )…...

PHP和Node.js哪个更爽?

先说结论&#xff0c;rust完胜。 php&#xff1a;laravel&#xff0c;swoole&#xff0c;webman&#xff0c;最开始在苏宁的时候写了几年php&#xff0c;当时觉得php真的是世界上最好的语言&#xff0c;因为当初活在舒适圈里&#xff0c;不愿意跳出来&#xff0c;就好比当初活在…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:

一、属性动画概述NETX 作用&#xff1a;实现组件通用属性的渐变过渡效果&#xff0c;提升用户体验。支持属性&#xff1a;width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项&#xff1a; 布局类属性&#xff08;如宽高&#xff09;变化时&#…...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

IGP(Interior Gateway Protocol,内部网关协议)

IGP&#xff08;Interior Gateway Protocol&#xff0c;内部网关协议&#xff09; 是一种用于在一个自治系统&#xff08;AS&#xff09;内部传递路由信息的路由协议&#xff0c;主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

2024年赣州旅游投资集团社会招聘笔试真

2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!

5月28日&#xff0c;中天合创屋面分布式光伏发电项目顺利并网发电&#xff0c;该项目位于内蒙古自治区鄂尔多斯市乌审旗&#xff0c;项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站&#xff0c;总装机容量为9.96MWp。 项目投运后&#xff0c;每年可节约标煤3670…...

Caliper 配置文件解析:config.yaml

Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

技术栈RabbitMq的介绍和使用

目录 1. 什么是消息队列&#xff1f;2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...

Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成

一个面向 Java 开发者的 Sring-Ai 示例工程项目&#xff0c;该项目是一个 Spring AI 快速入门的样例工程项目&#xff0c;旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计&#xff0c;每个模块都专注于特定的功能领域&#xff0c;便于学习和…...