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

绿化公司和苗圃做网站/网店培训教程

绿化公司和苗圃做网站,网店培训教程,网站开发公司oa,响应式网页制作教程目录 1、生产消费者模型示意图 2、生产者消费者之间的关系 3、定义交易场所 4、实现生产消费者模型 5、伪唤醒 6、多生产多消费者的实际运用 7、POSIX信号量 7.1 初始化信号量 7.2 销毁信号量 7.3 等待信号量 7.4 发布信号量 8、生产消费的环形队列模型 8.1…

目录

1、生产消费者模型示意图

2、生产者消费者之间的关系 

3、定义交易场所

4、实现生产消费者模型

5、伪唤醒

6、多生产多消费者的实际运用 

7、POSIX信号量 

7.1 初始化信号量 

7.2 销毁信号量  

7.3 等待信号量

7.4 发布信号量

8、生产消费的环形队列模型

8.1 实现多生产多消费环形模型

结语


前言:

        使用生产消费者模型的原因如下:生产消费者模型常用于多线程并发式执行流,该模型具有同步与互斥机制。该模型的核心点在于用一个容器作为生产者和消费者相互通信的桥梁,使得生产者和消费者不直接进行交互,降低了生产者与消费者之间的强耦合度。好处在于生产者生产数据后即使消费者不来拿这个数据,生产者也可以继续生产,并且后续生产的数据不会覆盖之前的数据,只有当容器满了,生产者才会阻塞。只要容器内有数据,消费者就可以从容器中拿数据,无需等待生产者一个一个的生产数据。

1、生产消费者模型示意图

         生产消费者模型具体示意图如下:

2、生产者消费者之间的关系 

         生产消费者模型具有互斥机制,因此生产者和消费者之间肯定存在互斥概念,这里例举3个关系(关系指的是生产者对交易场所的操作和消费者对交易场所的操作之间的关系,简写成生产者和消费者的关系):

1、生产者和消费者的关系必须是互斥和同步的,当生产者访问交易场所时消费者不能访问交易场所,只有当生产者访问结束后消费者才可访问交易场所,即访问具有原子性。

2、生产者和生产者之间也是互斥,他们的关系是类似竞争。

3、消费者和消费者之间也是互斥,比如一个资源只能让一个消费者获取,则另一个消费者就获取不了了。

        综上所述可以发现生产者消费者在代码层面上是共享一把锁的。 

3、定义交易场所

        这里用队列来模拟交易场所,入队表示生产者访问场所,出队表示消费者访问场所。生产者和消费者就是两个线程,入队和出队是这两个线程要执行的操作。所以需要自己实现一个队列,并且对该队列的入队和出队进行同步互斥约束。

        将队列封装成一个类,自定义队列代码如下:

#pragma once
#include <iostream>
#include <queue>
#include <pthread.h>
#include <unistd.h>
using namespace std;template <class T>
class BlockQueue
{static const int defalutnum = 5;//队列的大小
public:BlockQueue(int maxcap = defalutnum):maxcap_(maxcap){pthread_mutex_init(&mutex_, nullptr);pthread_cond_init(&c_cond_, nullptr);pthread_cond_init(&p_cond_, nullptr);}//出队-消费者T pop(){pthread_mutex_lock(&mutex_);if(q_.size() == 0) {pthread_cond_wait(&c_cond_, &mutex_); //场所为空则消费者必须等待}T out = q_.front(); q_.pop();//消费了一个数据pthread_cond_signal(&p_cond_); //唤醒生产者pthread_mutex_unlock(&mutex_);return out;}//入队-生产者void push(const T &in){pthread_mutex_lock(&mutex_);if(q_.size() == maxcap_){ pthread_cond_wait(&p_cond_, &mutex_); //场所为满则生产者必须等待}// 1. 队列没满 2.被唤醒 q_.push(in);//生产了一个数据                pthread_cond_signal(&c_cond_);//唤醒消费者pthread_mutex_unlock(&mutex_);}~BlockQueue(){pthread_mutex_destroy(&mutex_);pthread_cond_destroy(&c_cond_);pthread_cond_destroy(&p_cond_);}
private:std::queue<T> q_; // 复用容器队列int maxcap_;      // 队列大小pthread_mutex_t mutex_;//生产者和消费者共用一把锁,因为他们的互斥的pthread_cond_t c_cond_;//消费者的等待队列pthread_cond_t p_cond_;//生产者的等待队列
};

        上述代码的逻辑:刚开始消费者会先进入条件变量的等待队列中等待(等待时消费者会释放锁),生产者此时就申请到锁了,然后生产一个数据,只要场所里有了数据,就消费者就可以来拿数据,因此生产者进行入队操作后,就可以唤醒在等待队列里的消费者了。相反消费者只要出队了一个数据,表示场所里有剩余空间,消费者就可以唤醒生产者来生产数据了。

        注意:采用的唤醒策略是交互性唤醒

        小细节:虽然唤醒了对方,但是不意味着唤醒了那一刻对面就拿到锁了,而是自己要先释放锁对方才能申请到锁,对方申请到锁了才可以从等待队列中出来。

4、实现生产消费者模型

        有了上面的自定义栈结构,后续只需要在生产者线程中调用push函数,消费者线程中调用pop函数即可,实现生产消费者模型代码如下: 

#include "queue.hpp"void *Consumer(void *args)
{BlockQueue<int> *bq = static_cast<BlockQueue<int> *>(args);while (true){int t = bq->pop();//消费者消费数据cout<<"消费者拿到一个数据"<<t<<endl;sleep(1);}
}void *Productor(void *args)
{BlockQueue<int> *bq = static_cast<BlockQueue<int> *>(args);int num = 0;while (true){bq->push(num);//生产者生产数据cout<<"生产者生产一个数据"<<num<<endl;num++;}
}int main()
{BlockQueue<int> *bq = new BlockQueue<int>();pthread_t c, p;pthread_create(&c, nullptr, Consumer, bq);pthread_create(&p, nullptr, Productor, bq);pthread_join(c, nullptr);pthread_join(p, nullptr);delete bq;return 0;
}

        运行结果:


         从上述结果可以分析出两个关键点:

        1、为什么是生产者先生产了5个数据,然后消费者才过来消费,而不是生产一个数据消费者就来消费。

        答:因为上述代码中没有对生产者的循环调用进行sleep,并且生产者和消费者共用一把锁,在最开始的时候消费者会先触发条件变量(因为交易场所为空),会直接进入消费等待队列中。而生产者申请到锁后并不会触发条件变量(因为交易场所未满),所以生产者就可以拿着锁去访问临界资源,当他唤醒消费者等待队列并且释放锁后,此时还是他距离锁最近的(因为在代码中他释放锁之后的动作就是申请锁),因为生产者释放锁后没有对其进行任何的sleep,因此生产者在此时是对锁拥有最高优先级。 

        具体逻辑图如下:

        2、为什么消费者消费一次数据后就可以直接唤醒生产者呢?

        答:因为消费者调用完pop函数后sleep了1秒,导致消费者不再“离锁最近”,并且消费者消费数据后对生产者进行了唤醒,所以生产者的等待队列中没有任何线程跟其竞争锁,最终生产者被成功唤醒并申请到了锁,并执行push代码。

         具体逻辑图如下:

5、伪唤醒

        伪唤醒指的是当线程在等待队列中被唤醒了,实际上当前条件并不满足于该线程被唤醒,此时就会导致意料之外的错误,所以在线程被唤醒时,最好先检查一下当前的条件是否满足,因此上面代码中唤醒的条件应该从if改成while,以便防止伪唤醒发生,特别是在多生产多消费的情况下。

        防止伪唤醒的代码如下: 

 T pop(){pthread_mutex_lock(&mutex_);while(q_.size() == 0)//防止伪唤醒{pthread_cond_wait(&c_cond_, &mutex_); //场所为空则消费者必须等待}T out = q_.front(); q_.pop();//消费了一个数据pthread_cond_signal(&p_cond_); //唤醒生产者pthread_mutex_unlock(&mutex_);return out;}void push(const T &in){pthread_mutex_lock(&mutex_);while(q_.size() == maxcap_)//防止伪唤醒{ pthread_cond_wait(&p_cond_, &mutex_); //场所为满则生产者必须等待}// 1. 队列没满 2.被唤醒 q_.push(in);//生产了一个数据                pthread_cond_signal(&c_cond_);//唤醒消费者pthread_mutex_unlock(&mutex_);}

        举例说明伪唤醒的错误:在多生产的场景下,当我们只需要生产一个数据时,多个生产者竞争一个锁确实可以只生产一个数据,但是当这个竞争到锁的生产者释放锁时,该锁并不会被消费者拿到,而是被等待队列中另一个生产者申请到锁,就会导致数据溢出的风险。因为多个生产者是处于同一个条件变量的等待队列中,当其中某个生产者重新调用wait函数回到该队列中时,他会释放锁,但是这个锁不会被他唤醒的消费者先申请到,而是被他所在队列的其他生产者拿到,这就导致其他生产者继续向满的队列生产。(总而言之,伪唤醒是一种不稳定的唤醒方式,伪唤醒的出现和系统调度已经线程竞争条件都有关系,因此当多线程的情况变得复杂时要注意防护伪唤醒

6、多生产多消费者的实际运用 

        在实际项目中,生产者通常是给消费者派发各种任务,有了生产消费者模型,就可以把这些任务写进交易场所中,然后消费者到场所中领取任务并执行,因此我们可以先定义一个任务类,用于任务的派发和执行。

        任务类的代码如下:

#pragma once
#include <iostream>
#include <string>std::string opers="+-*/%";//随机运算符号enum{DivZero=1,ModZero,Unknown
};class Task
{
public:Task(int x, int y, char op) : data1_(x), data2_(y), oper_(op), result_(0), exitcode_(0){}void run(){switch (oper_){case '+':result_ = data1_ + data2_;break;case '-':result_ = data1_ - data2_;break;case '*':result_ = data1_ * data2_;break;case '/':{if(data2_ == 0) exitcode_ = DivZero;//除0错误else result_ = data1_ / data2_;}break;case '%':{if(data2_ == 0) exitcode_ = ModZero;//模0错误else result_ = data1_ % data2_;}            break;default:exitcode_ = Unknown;break;}}void operator ()()//实现函数重载{run();}std::string GetResult(){std::string r = std::to_string(data1_);r += oper_;r += std::to_string(data2_);r += "=";r += std::to_string(result_);r += "[code: ";r += std::to_string(exitcode_);r += "]";return r;}std::string GetTask()//将任务转成字符串的形式,方便打印{std::string r = std::to_string(data1_);r += oper_;r += std::to_string(data2_);r += "=?";return r;}~Task(){}private:int data1_;int data2_;char oper_;int result_;//计算结果int exitcode_;//退出码
};

        主函数执行生产消费者代码如下:

#include "queue.hpp"
#include "task.hpp"
#include <unistd.h>
#include <ctime>void *Consumer(void *args)
{BlockQueue<Task> *bq = static_cast<BlockQueue<Task> *>(args);while (true){// 消费Task t = bq->pop();// 计算t();std::cout << "处理任务: " << t.GetTask() << " 运算结果是: " \<< t.GetResult() << " thread id: " << pthread_self() << std::endl;}
}void *Productor(void *args)
{int len = opers.size();BlockQueue<Task> *bq = static_cast<BlockQueue<Task> *>(args);int x = 10;int y = 20;while (true){// 模拟生产者生产数据int data1 = rand() % 10 + 1;//随机数usleep(10);int data2 = rand() % 10;//随机数char op = opers[rand() % len];//随机运算符号Task t(data1, data2, op);// 生产bq->push(t);std::cout << "生产了一个任务: " << t.GetTask() << " thread id: " \<< pthread_self() << std::endl;sleep(1);}
}int main()
{srand(time(nullptr));BlockQueue<Task> *bq = new BlockQueue<Task>();pthread_t c[3], p[5];for (int i = 0; i < 3; i++){pthread_create(c + i, nullptr, Consumer, bq);}for (int i = 0; i < 5; i++){pthread_create(p + i, nullptr, Productor, bq);}for (int i = 0; i < 3; i++){pthread_join(c[i], nullptr);}for (int i = 0; i < 5; i++){pthread_join(p[i], nullptr);}delete bq;return 0;
}

        运行结果:

7、POSIX信号量 

         POSIX信号量可以让多个线程访问同一个交易场所的不同区域,也就是说在这种情况下生产者和消费者不存在互斥,因为他们访问的是场所内不同的资源空间,当POSIX信号量为0时表示当前线程不能往下访问临界资源

7.1 初始化信号量 

        接口介绍如下:

#include <semaphore.h>int sem_init(sem_t *sem, int pshared, unsigned int value);
//sem表示要初始化的信号量
//pshared为0表示线程间共享,非零表示进程间共享
//value表示信号量初始值

         初始化信号量时,必须先定义一个类型为sem_t的信号量变量。

7.2 销毁信号量  

        接口介绍如下:

int sem_destroy(sem_t *sem);//销毁一个信号量

7.3 等待信号量

        接口介绍如下:

int sem_wait(sem_t *sem);//等待信号量,会将信号量的值减1

7.4 发布信号量

         接口介绍如下:

int sem_post(sem_t *sem);//将信号量值加1

8、生产消费的环形队列模型

        上面的生产消费模型用的是队列作为容器,现在用数组取模的方式模拟环形队列作为生产消费模型的交易场所,示意图如下:

        上图表示交易场所为空时,生产者和消费者相遇,这时候生产者和消费者只有生产者可以往前走(生产者信号量不为0),因为场所内没有数据(消费者信号量为0),所以消费者无法消耗数据,也就无法往前走。


        当交易场所满的情况如下:

        可以发现当交易场所满的时候,生产者依然是和消费者指向同一块区域,并且此时也只有一方可以移动,即只有消费者可以移动(消费者信号量不为0,而生产者信号量为0),因为当前没有空间让生产者生产数据了,只能让消费者消费数据。


        以上是空或满的情况,当然,只要消费者没有和生产者相遇,那么他们两个可以同时对交易场所进行操作,因为这种情况他们两个的信号量都不为0,而这是上述自定义队列办不到的,这也是POSIX信号量的优势,只有当交易场所为空或为满时(其中一方的信号量为0时),生产者和消费者才是互斥关系。 

8.1 实现多生产多消费环形模型

        首先先定义一个环形队列,逻辑和上面自定义队列的类是一样的,只不过环形队列用的是vector来当作容器,并且使用信号量约束生产者和消费者,代码如下:

#pragma once
#include <iostream>
#include <vector>
#include <semaphore.h>
#include <pthread.h>const static int defaultcap = 5;template<class T>
class RingQueue{
private:void P(sem_t &sem)//--信号量{sem_wait(&sem);}void V(sem_t &sem)//++信号量{sem_post(&sem);}void Lock(pthread_mutex_t &mutex){pthread_mutex_lock(&mutex);}void Unlock(pthread_mutex_t &mutex){pthread_mutex_unlock(&mutex);}
public:RingQueue(int cap = defaultcap):ringqueue_(cap), cap_(cap), c_step_(0), p_step_(0){sem_init(&cdata_sem_, 0, 0);sem_init(&pspace_sem_, 0, cap);pthread_mutex_init(&c_mutex_, nullptr);pthread_mutex_init(&p_mutex_, nullptr);}void Push(const T &in) // 生产{P(pspace_sem_);Lock(p_mutex_); // ?ringqueue_[p_step_] = in;// 位置后移,维持环形特性p_step_++;p_step_ %= cap_;Unlock(p_mutex_); V(cdata_sem_);}void Pop(T *out)       // 消费{P(cdata_sem_);Lock(c_mutex_); // ?*out = ringqueue_[c_step_];// 位置后移,维持环形特性c_step_++;c_step_ %= cap_;Unlock(c_mutex_); V(pspace_sem_);}~RingQueue(){sem_destroy(&cdata_sem_);sem_destroy(&pspace_sem_);pthread_mutex_destroy(&c_mutex_);pthread_mutex_destroy(&p_mutex_);}
private:std::vector<T> ringqueue_;int cap_;int c_step_;       // 消费者下标int p_step_;       // 生产者下标sem_t cdata_sem_;  // 消费者关注的数据资源sem_t pspace_sem_; // 生产者关注的空间资源pthread_mutex_t c_mutex_;pthread_mutex_t p_mutex_;
};

         信号量的使用逻辑:生成一个数据,则生成者的信号量减减,消费者的信号量加加。相反,消费一个数据,则消费者的信号量减减,生成者的信号量加加。


        主函数实现生成消费数据的代码如下(注意这里的任务列表依旧用上文的任务类,只不过加了一个默认构造):

#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <ctime>
#include "sem.hpp"
#include "task.hpp"using namespace std;struct ThreadData
{RingQueue<Task> *rq;std::string threadname;
};void *Productor(void *args)
{// sleep(3);ThreadData *td = static_cast<ThreadData*>(args);RingQueue<Task> *rq = td->rq;std::string name = td->threadname;int len = opers.size();while (true){// 1. 获取数据int data1 = rand() % 10 + 1;usleep(10);int data2 = rand() % 10;char op = opers[rand() % len];Task t(data1, data2, op);// 2. 生产数据rq->Push(t);cout << "生成任务完毕 : " << t.GetTask() << " : " << name << endl;sleep(1);}return nullptr;
}void *Consumer(void *args)
{ThreadData *td = static_cast<ThreadData*>(args);RingQueue<Task> *rq = td->rq;std::string name = td->threadname;while (true){// 1. 消费数据Task t;rq->Pop(&t);// 2. 处理数据t();cout << "消费者拿到一个任务 : " << t.GetTask() << " : " << name << " 结果: " << t.GetResult() << endl;sleep(1);}return nullptr;
}int main()
{srand(time(nullptr) ^ getpid());RingQueue<Task> *rq = new RingQueue<Task>(50);pthread_t c[5], p[3];for (int i = 0; i < 1; i++){ThreadData *td = new ThreadData();td->rq = rq;td->threadname = "Productor-" + std::to_string(i);pthread_create(p + i, nullptr, Productor, td);}for (int i = 0; i < 1; i++){ThreadData *td = new ThreadData();td->rq = rq;td->threadname = "Consumer-" + std::to_string(i);pthread_create(c + i, nullptr, Consumer, td);}for (int i = 0; i < 1; i++){pthread_join(p[i], nullptr);}for (int i = 0; i < 1; i++){pthread_join(c[i], nullptr);}return 0;
}

        运行结果:

结语

        以上就是关于生产消费者模型的讲解,生产消费者模型可以提高并发式执行程序的效率,他的核心点在于交易场所的设计,以及生产者和消费者访问场所的时机,若时机出现偏差则会导致线程对锁的竞争不公平。

        最后如果本文有遗漏或者有误的地方欢迎大家在评论区补充,谢谢大家!! 

相关文章:

Linux_生产消费者模型

目录 1、生产消费者模型示意图 2、生产者消费者之间的关系 3、定义交易场所 4、实现生产消费者模型 5、伪唤醒 6、多生产多消费者的实际运用 7、POSIX信号量 7.1 初始化信号量 7.2 销毁信号量 7.3 等待信号量 7.4 发布信号量 8、生产消费的环形队列模型 8.1…...

【Vue】`v-if` 指令详解:条件渲染的高效实现

文章目录 一、v-if 指令概述二、v-if 的基本用法1. 基本用法2. 使用 v-else3. 使用 v-else-if 三、v-if 指令的高级用法1. 与 v-for 一起使用2. v-if 的性能优化 四、v-if 的常见应用场景1. 表单验证2. 弹窗控制 五、v-if 指令的注意事项 Vue.js 是一个用于构建用户界面的渐进式…...

junit mockito Base基类

编写单元测试时我们都习惯性减少重复代码 以下基于spring mvc框架&#xff0c;需要手动pom导包 BaseTest类用于启动上下文进行debug调试 MockBaseTset类用于不启动上下文进行打桩mock pom.xml <dependency><groupId>org.mockito</groupId><artifactId…...

朋友圈运营分享干货2

朋友圈发什么内容&#xff1f; 1、产品相关 产品服务&#xff1a;产品的内容要有“用户视角”从用户的使用痛点入手&#xff0c;写到用户心坎里&#xff0c;才能引发购买 买家秀&#xff1a;买家秀是很好的朋友圈索材&#xff0c;可以让用户有一个正面感知清楚了解工品的情况…...

linux中创建一个名为“thread1“,堆栈大小为1024,优先级为2的线程

在Linux中&#xff0c;直接创建一个具有特定堆栈大小和优先级的线程通常不是通过标准的POSIX线程&#xff08;pthread&#xff09;库直接支持的。POSIX线程库&#xff08;pthread&#xff09;提供了创建和管理线程的基本机制&#xff0c;但不直接支持设置线程的堆栈大小或优先级…...

架构以及架构中的组件

架构以及架构中的组件 Transform Transform 以下的代码包含&#xff1a; 标准化的示例残差化的示例 # huggingface # transformers# https://www.bilibili.com/video/BV1At4y1W75x?spm_id_from333.999.0.0import copy import math from collections import namedtupleimport …...

Docker启动PostgreSql并设置时间与主机同步

在 Docker 中启动 PostgreSql 时&#xff0c;需要配置容器的时间与主机同步。可以通过在 Dockerfile 或者 Docker Compose 文件中设置容器的时区&#xff0c;或者使用宿主机的时间来同步容器的时间。这样可以确保容器中的 PostgreSql 与主机的时间保持一致&#xff0c;避免在使…...

提升无线网络安全:用Python脚本发现并修复WiFi安全问题

文章目录 概要环境准备技术细节3.1 实现原理3.2 创建python文件3.3 插入内容3.4 运行python脚本 加固建议4.1 选择强密码4.2 定期更换密码4.3 启用网络加密4.4 关闭WPS4.5 隐藏SSID4.6 限制连接设备 小结 概要 在本文中&#xff0c;我们将介绍并展示如何使用Python脚本来测试本…...

#三元运算符(python/java/c)

引入&#xff1a;什么是三元运算符呢&#xff1f;无疑其操作元有三个&#xff0c;一个是条件表达式&#xff0c;剩余两个为值&#xff0c;条件表达式为真时运算取第一个值&#xff0c;为假时取第二个值。 一 Python true_expression if condition else false_expressi…...

探索Python自然语言处理的新篇章:jionlp库介绍

探索Python自然语言处理的新篇章&#xff1a;jionlp库介绍 1. 背景&#xff1a;为什么选择jionlp&#xff1f; 在Python的生态中&#xff0c;自然语言处理&#xff08;NLP&#xff09;是一个活跃且不断发展的领域。jionlp是一个专注于中文自然语言处理的库&#xff0c;它提供了…...

Deepin系统,中盛科技温湿度模块读温度纯c程序(备份)

#include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <termios.h>int main() {int fd;struct termios options;// 打开串口设备fd open("/dev/ttyMP0", O_RDWR | O_NOCTTY|O_NDELAY); //O_NDELAY:打开设备不阻塞//O_NOCTT…...

文件包含漏洞: 函数,实例[pikachu_file_inclusion_local]

文件包含 文件包含是一种较为常见技术&#xff0c;允许程序员在不同的脚本或程序中重用代码或调用文件 主要作用和用途&#xff1a; 代码重用&#xff1a;通过将通用函数或代码段放入单独的文件中&#xff0c;可以在多个脚本中包含这些文件&#xff0c;避免重复编写相同代码。…...

学习计划2024下半年

基础&#xff1a; 学习《算法第4版》&#xff0c;学习leetcode上的面试经典150题&#xff0c;使用C完成&#xff1b;再看一般《深入理解计算机系统》语言&#xff1a; 学习go语言&#xff0c;并且用它写一个小软件(还没想好什么),写一个pingtool程序编程思想&#xff1a; 阅读经…...

RabbitMQ的学习和模拟实现|sqlite轻量级数据库的介绍和简单使用

SQLite3 项目仓库&#xff1a;https://github.com/ffengc/HareMQ SQLite3 什么是SQLite为什么需要用SQLite官方文档封装Helper进行一些实验 什么是SQLite SQLite是一个进程内的轻量级数据库&#xff0c;它实现了自给自足的、无服务器的、零配置的、事务性的 SQL数据库引擎…...

AI批量剪辑,批量发布大模型矩阵系统搭建开发

目录 前言 一、AI矩阵系统功能 二、AI批量剪辑可以解决什么问题&#xff1f; 总结&#xff1a; 前言 基于ai生成或剪辑视频的原理&#xff0c;利用ai将原视频进行混剪&#xff0c;生成新的视频素材。ai会将剪辑好的视频加上标题&#xff0c;批量发布到各个自媒体账号上。这…...

SpringMVC源码深度解析(中)

接上一遍博客《SpringMVC源码深度解析(上)》继续聊。最后聊到了SpringMVC的九大组建的初始化&#xff0c;以 HandlerMapping为例&#xff0c;SpringMVC提供了三个实现了&#xff0c;分别是&#xff1a;BeanNameUrlHandlerMapping、RequestMappingHandlerMapping、RouterFunctio…...

Mojo模型动态批处理:智能预测的终极武器

标题&#xff1a;Mojo模型动态批处理&#xff1a;智能预测的终极武器 在机器学习领域&#xff0c;模型的灵活性和可扩展性是至关重要的。Mojo模型&#xff08;Model-as-a-Service&#xff09;提供了一种将机器学习模型部署为服务的方式&#xff0c;允许开发者和数据科学家轻松…...

人、智能、机器人……

在遥远的未来之城&#xff0c;智能时代如同晨曦般照亮了每一个角落&#xff0c;万物互联&#xff0c;机器智能与人类智慧交织成一幅前所未有的图景。这座城市&#xff0c;既是科技的盛宴&#xff0c;也是人性与情感深刻反思的舞台。 寓言&#xff1a;《智光与心影》 在智能之…...

SpringCloud------Sentinel(微服务保护)

目录 雪崩问题 处理方式!!!技术选型 Sentinel 启动命令使用步骤引入依赖配置控制台地址 访问微服务触发监控 限流规则------故障预防流控模式流控效果 FeignClient整合Sentinel线程隔离-------故障处理线程池隔离和信号量隔离​编辑 两种方式优缺点设置方式 熔断降级-----…...

【无标题】Elasticsearch for windows

一、windows安装Elasticsearch 1、Elasticsearch&#xff1a;用于存储数据、计算和搜索&#xff1b; 2、Logstash/Beats&#xff1a;用于数据搜集 3、Kibana&#xff1a;用于数据可视化 以上三个被称为ELK&#xff0c;常用语日志搜集、系统监控和状态分析 Elasticsearch安…...

Yolo-World网络模型结构及原理分析(一)——YOLO检测器

文章目录 概要一、整体架构分析二、详细结构分析YOLO检测器1. Backbone2. Head3.各模块的过程和作用Conv卷积模块C2F模块BottleNeck模块SPPF模块Upsampling模块Concat模块 概要 尽管YOLO&#xff08;You Only Look Once&#xff09;系列的对象检测器在效率和实用性方面表现出色…...

WEB前端06-BOM对象

BOM浏览器对象模型 浏览器对象模型&#xff1a;将浏览器的各个组成部分封装成对象。是用于描述浏览器中对象与对象之间层次关系的模型&#xff0c;提供了独立于页面内容、并能够与浏览器窗口进行交互的对象结构。 组成部分 Window&#xff1a;浏览器窗口对象 Navigator&…...

Android11 framework 禁止三方应用开机自启动

Android11应用自启动限制 大纲 Android11应用自启动限制分析验证猜想&#xff1a;Android11 AOSP是否自带禁止三方应用监听BOOT_COMPLETED​方案禁止执行非系统应用监听到BOOT_COMPLETED​后的代码逻辑在执行启动时判断其启动的广播接收器一棍子打死方案&#xff08;慎用&#…...

Java | Leetcode Java题解之第263题丑数

题目&#xff1a; 题解&#xff1a; class Solution {public boolean isUgly(int n) {if (n < 0) {return false;}int[] factors {2, 3, 5};for (int factor : factors) {while (n % factor 0) {n / factor;}}return n 1;} }...

将AWS RDS MySQL实例从存储未加密改为加密的方案

问题描述&#xff1a; 因为AWS RDS官方文档【1】中已经明确说明&#xff0c;MySQL RDS的存储为EBS卷&#xff0c;用KMS进行RDS加密有如下限制&#xff1a; 您只能在创建RDS的时候&#xff0c;选择加密。对于已经创建的RDS实例&#xff0c;您无法将为加密的实例&#xff0c;直…...

nginx的配置:TLSv1 TLSv1.1 被暴露不安全

要在 Nginx 配置中禁用不安全的 SSL 协议&#xff08;如 TLSv1 和 TLSv1.1&#xff09;&#xff0c;并仅启用更安全的协议&#xff08;如 TLSv1.2 和 TLSv1.3&#xff09;&#xff0c;您可以更新您的 Nginx 配置文件。下面是一个示例配置&#xff1a; # 位于 Nginx 配置文件 (…...

揭开黑箱:目标检测中可解释性的重要性与实现

揭开黑箱&#xff1a;目标检测中可解释性的重要性与实现 在深度学习的目标检测任务中&#xff0c;模型的准确性虽然重要&#xff0c;但模型的决策过程是否透明也同样关键。可解释性&#xff08;Explainability&#xff09;是指模型能够为其预测结果提供清晰、可理解的解释。本…...

Mysql高价语句

一.高级语法的查询语句 1.排序语法&#xff08;默认的排序方式就是升序&#xff09;。 升序ASC&#xff1a;select * from test01 order by name; 降序DESC&#xff1a;select * from test01 order by name desc; 多个列排序&#xff1a;以多个列作为排序&#xff0c;只有第一…...

ArcGIS Pro SDK (九)几何 6 包络

ArcGIS Pro SDK &#xff08;九&#xff09;几何 6 包络 文章目录 ArcGIS Pro SDK &#xff08;九&#xff09;几何 6 包络1 构造包络2 构造包络 - 从 JSON 字符串3 合并两个包络4 与两个包络相交5 展开包络6 更新包络的坐标 环境&#xff1a;Visual Studio 2022 .NET6 ArcGI…...

单链表<数据结构 C版>

目录 概念 链表的单个结点 链表的打印操作 新结点的申请 尾部插入 头部插入 尾部删除 头部删除 查找 在指定位置之前插入数据 在任意位置之后插入数据 测试运行一下&#xff1a; 删除pos结点 删除pos之后结点 销毁链表 概念 单链表是一种在物理存储结构上非连续、非顺序…...