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

香橙派5使用NPU加速yolov5的实时视频推理(二)

三、将best.onnx转为RKNN格式

        这一步就需要我们进入到Ubuntu20.04系统中了,我的Ubuntu系统中已经下载好了anaconda,使用anaconda的好处就是可以方便的安装一些库,而且还可以利用conda来配置虚拟环境,做到环境与环境之间相互独立。

        对于我来说,使用了以下命令创建了一个名为rknn_ceshi的虚拟环境

conda create -n rknn_ceshi python=3.8

        之后,点击GitHub - rockchip-linux/rknn-toolkit2把整个项目给下载下来,解压后,我们进入刚刚创立虚拟环境下安装rknn-toolkit2。进入doc目录后,输入命令

pip install -r requirements_cp38-1.4.0.txt -i https://mirror.baidu.com/pypi/simple

        这里一定要带上百度的镜像源,要不然会报错,这个坑折磨了我整整3小时。

        安装完成后,出现下面的界面就说明已经安装好了

        接下来,我们进入packages文件夹,输入一下命令

pip install rknn_toolkit2-1.4.0_22dcfef4-cp38-cp38-linux_x86_64.whl

        出现以下界面,但是这里一定要注意,有一个超级大坑,超级大坑,超级大坑,后续我也是询问了大佬才解决的这个问题,这个地方安装的是rknn-toolkit2-1.4.0-22dcfef4!!!

        出现上面那个界面后,我们在终端输入python,再输入以下命令,如果没有报错,则证明我们的环境已经搭载好了

from rknn.api import RKNN

        接下来,我们要做的就是修改test.py里面的一些内容

        我第一次做的时候,报了错误,当时提示的是没有这个2-1.4.0-22dcfef4版本,我就跑到conda的环境包下,把所有的2-1.4.0-22dcfef4版本改成了2-1.4.0,才解决这个问题。

        可是当我这一次在执行这个文件的时候,就没报这个错误,直接就跑起来了。

        之后在我们的文件夹下出现了best.rknn这样就可以到香橙派5上部署了!!!

四、香橙派5部署rknn实现NPU加速YOLOV5视频推理

        这里给大家强调一下,我使用的是RKNN的python版本来实现NPU加速的,这里我们需要到Github上下载RKNN官方教程,下载完成后进入该文件夹,输入指令

cd /examples/onnx/yolov5

        进入文件夹后,创建一个名为demo.py的文件,将以下代码复制即可,我已经实现了实时视频为了保护隐私,这里我依旧采用官方的yolov5s.rknn模型,而没有用我自己的

import os
import urllib
import traceback
import time
import datetime as dt
import sys
import numpy as np
import cv2
from rknnlite.api import RKNNLiteRKNN_MODEL = 'yolov5s.rknn'
DATASET = './dataset.txt'QUANTIZE_ON = TrueOBJ_THRESH = 0.25
NMS_THRESH = 0.45
IMG_SIZE = 640CLASSES = ("person", "bicycle", "car", "motorbike ", "aeroplane ", "bus ", "train", "truck ", "boat", "traffic light","fire hydrant", "stop sign ", "parking meter", "bench", "bird", "cat", "dog ", "horse ", "sheep", "cow", "elephant","bear", "zebra ", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball", "kite","baseball bat", "baseball glove", "skateboard", "surfboard", "tennis racket", "bottle", "wine glass", "cup", "fork", "knife ","spoon", "bowl", "banana", "apple", "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza ", "donut", "cake", "chair", "sofa","pottedplant", "bed", "diningtable", "toilet ", "tvmonitor", "laptop	", "mouse	", "remote ", "keyboard ", "cell phone", "microwave ","oven ", "toaster", "sink", "refrigerator ", "book", "clock", "vase", "scissors ", "teddy bear ", "hair drier", "toothbrush ")def sigmoid(x):return 1 / (1 + np.exp(-x))def xywh2xyxy(x):# Convert [x, y, w, h] to [x1, y1, x2, y2]y = np.copy(x)y[:, 0] = x[:, 0] - x[:, 2] / 2  # top left xy[:, 1] = x[:, 1] - x[:, 3] / 2  # top left yy[:, 2] = x[:, 0] + x[:, 2] / 2  # bottom right xy[:, 3] = x[:, 1] + x[:, 3] / 2  # bottom right yreturn ydef process(input, mask, anchors):anchors = [anchors[i] for i in mask]grid_h, grid_w = map(int, input.shape[0:2])box_confidence = sigmoid(input[..., 4])box_confidence = np.expand_dims(box_confidence, axis=-1)box_class_probs = sigmoid(input[..., 5:])box_xy = sigmoid(input[..., :2])*2 - 0.5col = np.tile(np.arange(0, grid_w), grid_w).reshape(-1, grid_w)row = np.tile(np.arange(0, grid_h).reshape(-1, 1), grid_h)col = col.reshape(grid_h, grid_w, 1, 1).repeat(3, axis=-2)row = row.reshape(grid_h, grid_w, 1, 1).repeat(3, axis=-2)grid = np.concatenate((col, row), axis=-1)box_xy += gridbox_xy *= int(IMG_SIZE/grid_h)box_wh = pow(sigmoid(input[..., 2:4])*2, 2)box_wh = box_wh * anchorsbox = np.concatenate((box_xy, box_wh), axis=-1)return box, box_confidence, box_class_probsdef filter_boxes(boxes, box_confidences, box_class_probs):"""Filter boxes with box threshold. It's a bit different with origin yolov5 post process!# Argumentsboxes: ndarray, boxes of objects.box_confidences: ndarray, confidences of objects.box_class_probs: ndarray, class_probs of objects.# Returnsboxes: ndarray, filtered boxes.classes: ndarray, classes for boxes.scores: ndarray, scores for boxes."""boxes = boxes.reshape(-1, 4)box_confidences = box_confidences.reshape(-1)box_class_probs = box_class_probs.reshape(-1, box_class_probs.shape[-1])_box_pos = np.where(box_confidences >= OBJ_THRESH)boxes = boxes[_box_pos]box_confidences = box_confidences[_box_pos]box_class_probs = box_class_probs[_box_pos]class_max_score = np.max(box_class_probs, axis=-1)classes = np.argmax(box_class_probs, axis=-1)_class_pos = np.where(class_max_score >= OBJ_THRESH)boxes = boxes[_class_pos]classes = classes[_class_pos]scores = (class_max_score* box_confidences)[_class_pos]return boxes, classes, scoresdef nms_boxes(boxes, scores):"""Suppress non-maximal boxes.# Argumentsboxes: ndarray, boxes of objects.scores: ndarray, scores of objects.# Returnskeep: ndarray, index of effective boxes."""x = boxes[:, 0]y = boxes[:, 1]w = boxes[:, 2] - boxes[:, 0]h = boxes[:, 3] - boxes[:, 1]areas = w * horder = scores.argsort()[::-1]keep = []while order.size > 0:i = order[0]keep.append(i)xx1 = np.maximum(x[i], x[order[1:]])yy1 = np.maximum(y[i], y[order[1:]])xx2 = np.minimum(x[i] + w[i], x[order[1:]] + w[order[1:]])yy2 = np.minimum(y[i] + h[i], y[order[1:]] + h[order[1:]])w1 = np.maximum(0.0, xx2 - xx1 + 0.00001)h1 = np.maximum(0.0, yy2 - yy1 + 0.00001)inter = w1 * h1ovr = inter / (areas[i] + areas[order[1:]] - inter)inds = np.where(ovr <= NMS_THRESH)[0]order = order[inds + 1]keep = np.array(keep)return keepdef yolov5_post_process(input_data):masks = [[0, 1, 2], [3, 4, 5], [6, 7, 8]]anchors = [[10, 13], [16, 30], [33, 23], [30, 61], [62, 45],[59, 119], [116, 90], [156, 198], [373, 326]]boxes, classes, scores = [], [], []for input, mask in zip(input_data, masks):b, c, s = process(input, mask, anchors)b, c, s = filter_boxes(b, c, s)boxes.append(b)classes.append(c)scores.append(s)boxes = np.concatenate(boxes)boxes = xywh2xyxy(boxes)classes = np.concatenate(classes)scores = np.concatenate(scores)nboxes, nclasses, nscores = [], [], []for c in set(classes):inds = np.where(classes == c)b = boxes[inds]c = classes[inds]s = scores[inds]keep = nms_boxes(b, s)nboxes.append(b[keep])nclasses.append(c[keep])nscores.append(s[keep])if not nclasses and not nscores:return None, None, Noneboxes = np.concatenate(nboxes)classes = np.concatenate(nclasses)scores = np.concatenate(nscores)return boxes, classes, scoresdef draw(image, boxes, scores, classes, fps):"""Draw the boxes on the image.# Argument:image: original image.boxes: ndarray, boxes of objects.classes: ndarray, classes of objects.scores: ndarray, scores of objects.fps: int.all_classes: all classes name."""for box, score, cl in zip(boxes, scores, classes):top, left, right, bottom = boxprint('class: {}, score: {}'.format(CLASSES[cl], score))print('box coordinate left,top,right,down: [{}, {}, {}, {}]'.format(top, left, right, bottom))top = int(top)left = int(left)right = int(right)bottom = int(bottom)cv2.rectangle(image, (top, left), (right, bottom), (255, 0, 0), 2)cv2.putText(image, '{0} {1:.2f}'.format(CLASSES[cl], score),(top, left - 6),cv2.FONT_HERSHEY_SIMPLEX,0.6, (0, 0, 255), 2)def letterbox(im, new_shape=(640, 640), color=(0, 0, 0)):# Resize and pad image while meeting stride-multiple constraintsshape = im.shape[:2]  # current shape [height, width]if isinstance(new_shape, int):new_shape = (new_shape, new_shape)# Scale ratio (new / old)r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])# Compute paddingratio = r, r  # width, height ratiosnew_unpad = int(round(shape[1] * r)), int(round(shape[0] * r))dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1]  # wh paddingdw /= 2  # divide padding into 2 sidesdh /= 2if shape[::-1] != new_unpad:  # resizeim = cv2.resize(im, new_unpad, interpolation=cv2.INTER_LINEAR)top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1))left, right = int(round(dw - 0.1)), int(round(dw + 0.1))im = cv2.copyMakeBorder(im, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color)  # add borderreturn im, ratio, (dw, dh)# ==================================
# 如下为改动部分,主要就是去掉了官方 demo 中的模型转换代码,直接加载 rknn 模型,并将 RKNN 类换成了 rknn_toolkit2_lite 中的 RKNNLite 类
# ==================================rknn = RKNNLite()# load RKNN model
print('--> Load RKNN model')
ret = rknn.load_rknn(RKNN_MODEL)# Init runtime environment
print('--> Init runtime environment')
# use NPU core 0 1 2
ret = rknn.init_runtime(core_mask=RKNNLite.NPU_CORE_0_1_2)
if ret != 0:print('Init runtime environment failed!')exit(ret)
print('done')# Create a VideoCapture object and read from input file
# If the input is the camera, pass 0 instead of the video file name
cap = cv2.VideoCapture(0)# Check if camera opened successfully
if (cap.isOpened()== False): print("Error opening video stream or file")# Read until video is completed
while(cap.isOpened()):start = dt.datetime.utcnow()# Capture frame-by-frameret, img = cap.read()if not ret:breakimg = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)img = cv2.resize(img, (IMG_SIZE, IMG_SIZE))# Inferenceprint('--> Running model')outputs = rknn.inference(inputs=[img])print('done')# post processinput0_data = outputs[0]input1_data = outputs[1]input2_data = outputs[2]input0_data = input0_data.reshape([3, -1]+list(input0_data.shape[-2:]))input1_data = input1_data.reshape([3, -1]+list(input1_data.shape[-2:]))input2_data = input2_data.reshape([3, -1]+list(input2_data.shape[-2:]))input_data = list()input_data.append(np.transpose(input0_data, (2, 3, 0, 1)))input_data.append(np.transpose(input1_data, (2, 3, 0, 1)))input_data.append(np.transpose(input2_data, (2, 3, 0, 1)))boxes, classes, scores = yolov5_post_process(input_data)duration = dt.datetime.utcnow() - startfps = round(10000000 / duration.microseconds)# draw process result and fpsimg_1 = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)cv2.putText(img_1, f'fps: {fps}',(20, 20),cv2.FONT_HERSHEY_SIMPLEX,0.6, (0, 125, 125), 2)if boxes is not None:draw(img_1, boxes, scores, classes, fps)# show outputcv2.imshow("post process result", img_1)# Press Q on keyboard to  exitif cv2.waitKey(25) & 0xFF == ord('q'):break# When everything done, release the video capture object
cap.release()# Closes all the frames
cv2.destroyAllWindows()

        这里我开启了CPU定频,可是并没有提高多少NPU的使用率,干脆我也不再把代码放上来了,等到以后有时间我再研究一下。

        之后在终端中,运行命令

python demo.py

        效果我放到了B站,感兴趣的小伙伴可以点进去看一下B站视频

相关文章:

香橙派5使用NPU加速yolov5的实时视频推理(二)

三、将best.onnx转为RKNN格式 这一步就需要我们进入到Ubuntu20.04系统中了&#xff0c;我的Ubuntu系统中已经下载好了anaconda&#xff0c;使用anaconda的好处就是可以方便的安装一些库&#xff0c;而且还可以利用conda来配置虚拟环境&#xff0c;做到环境与环境之间相互独立。…...

算法练习-二分查找(一)

算法练习-二分查找 1 代码实现 1.1 非递归实现 public int bsearch(int[] a, int n, int value) {int low 0;int high n - 1;while (low < high) {int mid (low high) / 2;if (a[mid] value) {return mid;} else if (a[mid] < value) {low mid 1} else {high …...

通用业务平台设计(五):预警平台建设

前言 在上家公司&#xff0c;随着业务的不断拓展(从支持单个国家单个主体演变成支持多个国家多个主体)&#xff0c;对预警的诉求越来越紧迫&#xff1b;如何保障业务的稳定性那&#xff1f;预警可以帮我们提前甄别风险&#xff0c;从而让我们可以在风险来临前将其消灭&#xff…...

Windows openssl-1.1.1d vs2017编译

工具&#xff1a; 1. perl&#xff08;https://strawberryperl.com/&#xff09; 2. nasm&#xff08;https://nasm.us/&#xff09; 3. openssl源码&#xff08;https://www.openssl.org/&#xff09; 可以自己去下载 或者我的网盘提供下载&#xff1a; 链接&#xff1a;…...

【深蓝学院】手写VIO第2章--IMU传感器--笔记

0. 内容 1. 旋转运动学 角速度的推导&#xff1a; 左ω∧\omega^{\wedge}ω∧&#xff0c;而ω\omegaω是在z轴方向运动&#xff0c;θ′[0,0,1]T\theta^{\prime}[0,0,1]^Tθ′[0,0,1]T 两边取模后得到结论&#xff1a; 线速度大小半径 * 角速度大小 其中&#xff0c;对旋转矩…...

网络基础(二)之HTTP与HTTPS

应用层 再谈 "协议" 协议是一种 "约定". socket api的接口, 在读写数据时, 都是按 "字符串" 的方式来发送接收的. 如果我们要传输一些"结构化的数据" 怎么办呢? 为什么要转换呢&#xff1f; 如果我们将struct message里面的信息…...

Python每日一练(20230306)

目录 1. 翻转二叉树 ★★ 2. 最长公共前缀 ★★ 3. 2的幂 ★ 1. 翻转二叉树 翻转一棵二叉树。 示例 1&#xff1a; 输入&#xff1a; 4/ \2 7/ \ / \ 1 3 6 9 输出&#xff1a; 4/ \7 2/ \ / \ 9 6 3 1示例 2&#xff1a; 输入&#xff1a; 1…...

C/C++每日一练(20230305)

目录 1. 整数分解 ☆ 2. 二叉树的最小深度 ★★ 3. 找x ★★ 1. 整数分解 输入一个正整数&#xff0c;将其按7进制位分解为各乘式的累加和。 示例 1&#xff1a; 输入&#xff1a;49 输出&#xff1a;497^2示例 2&#xff1a; 输入&#xff1a;720 输出&#xff1a;720…...

SAS字典的应用

数据字典中常用信息检索DICTIONARY.COLUMNS、DICTIONARY.TABLES以及DICTIONARY.MEMBERS等字典表的内容。在编程实践中&#xff0c;如何以SAS字典表来提高效率。 1、DICTIONARY.COLUMNS 对于当前SAS任务的全部数据集&#xff0c;表格DICTIONARY.COLUMNS包含了诸如变量的名称、类…...

Mysql中的函数和触发器

函数函数是什么&#xff1f;多用于查询语句&#xff0c;实现了某种功能&#xff1b;用途与存储过程不同&#xff0c;但语法是类似的&#xff1b;函数语法create function 函数名([参数列表]) returns 数据类型 begin DECLARE 变量&#xff1b; sql 语句; return 值; end; 设置函…...

分布式架构之(Zookeeper原理)

Zookeeper是一个典型的分布式数据一致性的结局方案&#xff0c;分布式应用程序可以基于它实现注入数据发布、订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master选举、分布式锁和分布式队列等功能&#xff0c; Zookeeper可以保证如下分布式一致性特性&#xff1a; 顺…...

Java框架学习 | MyBatis

问题导向学习MyBatis 为什么要有MyBatis框架&#xff1f; 避免Java开发者直接使用 JDBC重复做数据库操作&#xff0c;同时更便捷地实现想要的数据库相关功能&#xff0c;让Java专注于开发业务。 MyBatis框架如何实现该目的&#xff1f; MyBatis是半自动化持久层ORM框架&#x…...

Cookie+Session详解

文章目录批量删除会话技术简介CookieCookie 查看Cookie 的删除Cookie 使用页面获取 cookie 信息cookie 特点Sessionsession 的使用Session 登录权限验证过滤器简介过滤器的使用WebFilter 注解过滤放行登录权限验证批量删除 servlet 类 dao 层 会话技术 简介 在计算机领域…...

CAPL脚本要注意区分elcount和strlen求数组长度的区别,不然要吃大亏

&#x1f345; 我是蚂蚁小兵&#xff0c;专注于车载诊断领域&#xff0c;尤其擅长于对CANoe工具的使用&#x1f345; 寻找组织 &#xff0c;答疑解惑&#xff0c;摸鱼聊天&#xff0c;博客源码&#xff0c;点击加入&#x1f449;【相亲相爱一家人】&#x1f345; 玩转CANoe&…...

CSS常用选择器

目录 1.CSS是什么 2.CSS的三种写法 2.1内部样式 2.2内联样式 2.3外部样式 3.CSS选择器 3.1标签选择器 3.2类选择器(更好的选择) 3.3ID选择器 3.4后代选择器 3.5子选择器 3.6并集选择器 3.7伪类选择器(复合选择器的特殊用法) 1.CSS是什么 CSS全称Cascding Style Sh…...

Registry与DGC的攻击利用

0x01 2022-02-03写的一篇文章。 0x02 Registry Registry指的是RMI的注册表&#xff0c;攻击的目标是注册表所在的机器&#xff0c;一般注册表和RMI Server在同一个机器上&#xff0c;特殊情况下也会在不同机器上。 在我们通过LocateRegistry#getRegistry获取到目标开启的注…...

赛道持续降温!又一家自动驾驶公司裁员,市值曾超50亿美元

从去年下半年开始&#xff0c;自动驾驶赛道的裁员、倒闭风潮盛行。 本周&#xff0c;美股卡车自动驾驶上市公司Embark Trucks&#xff08;EMBK&#xff09;宣布将裁员70%&#xff0c;同时大幅缩减业务。“痛苦可能还没有结束&#xff0c;”公司首席执行官Alex Rodrigues在给员…...

路径规划 | 图解动态A*(D*)算法(附ROS C++/Python/Matlab仿真)

目录0 专栏介绍1 什么是D*算法&#xff1f;2 D*算法核心概念一览3 D*算法流程图4 步步图解&#xff1a;算法实例5 算法仿真与实现5.1 ROS C实现5.2 Python实现0 专栏介绍 &#x1f525;附C/Python/Matlab全套代码&#x1f525;课程设计、毕业设计、创新竞赛必备&#xff01;详…...

GraphCut、最大流最小割定理

G&#xff08;V&#xff0c;E&#xff09;&#xff1b;V为点集&#xff0c;E为边集&#xff1b; 节点集V中的节点分为&#xff1a; &#xff08;1&#xff09;终端节点。不包含图像像素&#xff0c;用S和T表示。S为源点&#xff0c;T为汇点。图像分割中通常用S表示前景目标&a…...

Word文档的密码忘记了怎么办?

Word文档可以设置两种密码&#xff0c;文件的“限制密码”和“打开密码”&#xff0c;今天来分享一下忘记这两种密码可以如何处理。 如果忘记的是Word文档的“限制密码”&#xff0c;文档就无法编辑及更改了&#xff0c;菜单目录中的相关选项也都是灰色状态&#xff0c;无法点…...

Android Wi-Fi 连接失败日志分析

1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分&#xff1a; 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析&#xff1a; CTR…...

线程与协程

1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指&#xff1a;像函数调用/返回一样轻量地完成任务切换。 举例说明&#xff1a; 当你在程序中写一个函数调用&#xff1a; funcA() 然后 funcA 执行完后返回&…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

微信小程序云开发平台MySQL的连接方式

注&#xff1a;微信小程序云开发平台指的是腾讯云开发 先给结论&#xff1a;微信小程序云开发平台的MySQL&#xff0c;无法通过获取数据库连接信息的方式进行连接&#xff0c;连接只能通过云开发的SDK连接&#xff0c;具体要参考官方文档&#xff1a; 为什么&#xff1f; 因为…...

让AI看见世界:MCP协议与服务器的工作原理

让AI看见世界&#xff1a;MCP协议与服务器的工作原理 MCP&#xff08;Model Context Protocol&#xff09;是一种创新的通信协议&#xff0c;旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天&#xff0c;MCP正成为连接AI与现实世界的重要桥梁。…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

聊一聊接口测试的意义有哪些?

目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开&#xff0c;首…...

Spring数据访问模块设计

前面我们已经完成了IoC和web模块的设计&#xff0c;聪明的码友立马就知道了&#xff0c;该到数据访问模块了&#xff0c;要不就这俩玩个6啊&#xff0c;查库势在必行&#xff0c;至此&#xff0c;它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据&#xff08;数据库、No…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

10-Oracle 23 ai Vector Search 概述和参数

一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI&#xff0c;使用客户端或是内部自己搭建集成大模型的终端&#xff0c;加速与大型语言模型&#xff08;LLM&#xff09;的结合&#xff0c;同时使用检索增强生成&#xff08;Retrieval Augmented Generation &#…...