文章目录 0 前言1 课题背景2 具体实现3 数据收集和处理3 MobileNetV2网络4 损失函数softmax 交叉熵4.1 softmax函数4.2 交叉熵损失函数 5 优化器SGD6 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是
🚩 **基于深度学习的植物识别算法 **
该项目较为新颖,适合作为竞赛课题方向,学长非常推荐!
🥇学长这里给一个题目综合评分(每项满分5分)
难度系数:3分工作量:4分创新点:4分 🧿 更多资料, 项目分享:
https://gitee.com/dancheng-senior/postgraduate
1 课题背景 植物在地球上是一种非常广泛的生命形式,直接关系到人类的生活环境,目前,植物识别主要依靠相关行业从业人员及有经验专家实践经验,工作量大、效率低。近年来,随着社会科技及经济发展越来越快,计算机硬件进一步更新,性能也日渐提高,数字图像采集设备应用广泛,设备存储空间不断增大,这样大量植物信息可被数字化。同时,基于视频的目标检测在模式识别、机器学习等领域得到快速发展,进而基于图像集分类方法研究得到发展。
本项目基于深度学习实现图像植物识别。
2 具体实现 3 数据收集和处理 数据是深度学习的基石
数据的主要来源有: 百度图片, 必应图片, 新浪微博, 百度贴吧, 新浪博客和一些专业的植物网站等
爬虫爬取的图像的质量参差不齐, 标签可能有误, 且存在重复文件, 因此必须清洗。清洗方法包括自动化清洗, 半自动化清洗和手工清洗。
自动化清洗包括:
滤除小尺寸图像.滤除宽高比很大或很小的图像.滤除灰度图像.图像去重: 根据图像感知哈希. 半自动化清洗包括:
图像级别的清洗: 利用预先训练的植物/非植物图像分类器对图像文件进行打分, 非植物图像应该有较低的得分; 利用前一阶段的植物分类器对图像文件 (每个文件都有一个预标类别) 进行预测, 取预标类别的概率值为得分, 不属于原预标类别的图像应该有较低的得分. 可以设置阈值, 滤除很低得分的文件; 另外利用得分对图像文件进行重命名, 并在资源管理器选择按文件名排序, 以便于后续手工清洗掉非植物图像和不是预标类别的图像.类级别的清洗 手工清洗: 人工判断文件夹下图像是否属于文件夹名所标称的物种, 这需要相关的植物学专业知识, 是最耗时且枯燥的环节, 但也凭此认识了不少的植物.
Excel是一种常见的电子表格文件格式,广泛用于数据记录和处理。Python提供了多个第三方库,可以方便地对Excel文件进行读写、数据操作和处理。本文将介绍如何使用Python对Excel文件进行处理,并提供相应的代码示例和详细说明。
一、安装第三方库 在开始之前,我们需要安装一些Python第三方库,用于对Excel文件进行处理。以下是常用的库:
pandas:用于数据分析和处理,支持读写Excel文件。
openpyxl:用于读写Excel文件。
xlrd:用于读取Excel文件。
xlwt:用于写入Excel文件。
可以使用pip命令进行安装:
pip install pandas openpyxl xlrd xlwt 安装完成后,我们可以开始使用这些库来处理Excel文件。
二、读取Excel文件 首先,我们需要导入相应的库。使用以下代码导入pandas和openpyxl:
import pandas as pd import openpyxl 2.1读取Excel文件到DataFrame 使用pandas库可以将Excel文件读取到DataFrame对象中,方便进行数据分析和处理。以下是一个示例代码:
# 读取Excel文件 data = pd.read_excel("data.xlsx") # 打印DataFrame print(data) 这段代码将data.xlsx文件读取到data变量中,并将其打印输出。你可以根据实际文件名和路径进行修改。
2.2读取指定Sheet的Excel文件 如果Excel文件中包含多个Sheet,你可以通过指定Sheet名称或索引来读取指定的Sheet。以下是一个示例代码:
# 读取指定Sheet的Excel文件 data = pd.read_excel("data.xlsx", sheet_name="Sheet1") # 打印DataFrame print(data) 这段代码将data.xlsx文件中名为"Sheet1"的Sheet读取到data变量中,并将其打印输出。你可以根据实际情况修改Sheet的名称或使用Sheet的索引。
三、写入Excel文件 除了读取Excel文件,我们还可以使用Python将数据写入Excel文件。以下是一个示例代码:
# 创建数据 data = { 'Name': ['Alice', 'Bob', 'Charlie'], 'Age': [25, 30, 35], 'City': ['New York', 'London', 'Paris'] } # 创建DataFrame df = pd.
探讨下几种SpringCloud权限实现方案,以zuul和shiro的思路做了实现,简写了搭建过程.
github地址GitHub - MeloFocus/FocusCloudWork
一.目标 1.外部请求统一从网关zuul进入,并且服务内部互相调用接口要校验权限
2.cloud和shiro结合,达到单点登录,和集中一个服务完成权限管理,其他业务服务不需要关注权限如何实现
3.其他服务依然可以控制权限细粒度到接口,如在接口上使用@RequirePermisson等注解,方便开发
二.思路 SpirngCloud zuul网关有两个作用,一个是分配路由,一个是过滤。zuul的过滤器作用有限,只能简单的做一些某个url是否能够访问之类的,无法像shiro一样细粒度到某个用户是否有某种权限;
shiro单体应用大家都会做,那变成微服务后,难道每个服务都要写一套shiro框架?这显然也太麻烦。这么几个思路:
1.在zuul服务里用shiro,做成动态url权限控制,就是把访问哪个url需要用什么权限,写入数据库,在过滤器读取与用户有的权限作对比;但是服务互相调用校验就行不通了,因为服务间调用不通过zuul
2.写一个服务专用于shiro认证和授权,包含用户、权限的curd,暴露出查询一个用户拥有什么权限的接口;在其他服务中,都写一个拦截器拿访问者token去授权服务拿此用户的权限,再跟请求的url对比;或者可以自定义注解用aop,注解标注的是访问此url需要什么权限,远程调用授权服务接口查询当前用户所有权限,与请求的url对比。
但是这个要自己实现拦截器。
3.第二种思路的简单版本。
server服务:专用于shiro认证和授权,包含用户、权限的curd,暴露出查询一个用户拥有什么权限的接口;
client项目:打成jar包供其他服务依赖,用shiro,client不同于server服务的是:
1.在realm中只有授权方法,没有认证方法,因为不需要client认证、需要server认证。将登陆地址配置为server服务的地址。这样未登录的用户都会跳转到server服务登录,想办法保存下原路径,登录成功后再返回原服务.并且client的realm授权方法是调用server服务接口查询权限,再返回给client项目的安全管理器。同时做成session共享 其他业务服务:只需要依赖于client。
这种思路来自于《跟我学shiro》的多项目集中权限,其实想想这种思路是可以的,shiro本质也是靠拦截器进行权限校验,虽然相当于每个服务都开启了一套shiro,但也就是容器中多了一些shiro拦截器和实例,而且可以用shiro的各种功能,开发方便。可以完成我们的三个目标。
三.具体实现 因为shiro和cloud的细节太多,这里就不赘述,以下内容默认读者掌握shiro和springcloud基本组件。
我使用的是Finchley.BUILD-SNAPSHOT版本。
我们建两个服务Base和Notice,Base负责权限认证,用户访问Notice服务时先跳转到Base服务校验。
1.建立基本eureka,zuul,服务Base,服务Notice 将服务Base、Notice、zuul注册到eureka,能够通过zuul访问两个服务,不再赘述。
贴一下zuul的配置:
server: port: 18900 spring: application: name: focus-zuul datasource: driverClassName: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/focus_cloud?useUnicode=true&characterEncoding=utf-8 username: root password: pangtiemin eureka: instance: prefer-ip-address: true #metadata-map: #zone: zone1 #此实例所处的zone client: #availability-zones: #可获得的region和其zone有哪些 #xian: zone1 #region: xian #此实例所处的 region serviceUrl: defaultZone: http://localhost:18800/eureka/ #zone1: http://localhost:18800/erueka zuul: #设置请求超时时间 connect-timeout-millis: 15000 #HTTP连接超时要比Hystrix的大 socket-timeout-millis: 60000 #socket超时 #SendErrorFilter: # error: # disable: true #禁用zuul默认的异常过滤器 errorControllerUrl: /error #自定义配置,异常处理接口 routes: focus-base: # 通过服务名serviceId路由,不通过具体的url path: /base/** serviceId: focus-base #默认敏感头是"
设置队列的优先级 设置消息的优先级
不公平分发
当预取值设置为 1 时,RabbitMQ 不会采用轮询分发的方式。相反,它会使用一种称为“自动应答”的机制来确保消息被正确地处理。
--------------------------------------------------------------------------------------------
rabbit基础系列
https://www.cnblogs.com/vipstone/p/9350075.html
RabbitMQ 其他知识点 | xustudyxu's Blog
RabbitMQ | 柏竹g
尚硅谷文档下面这个
RabbitMQ 其他知识点 | xustudyxu's Blog
springboot实战
springboot整合rabbitmq的发布确认,消费者手动返回ack,设置备用队列,以及面试题:rabbitmq确保消息不丢失_springboot rabbitmq如何确认消息发送成功-CSDN博客
RabbitMQ--集成Springboot--3.2--消息确认机制_java onmessage方法中实现手动确认-CSDN博客
消息问题解决方案
消息中间件MQ场景常见问题(消息丢失,重复消费,垃圾消息,延时消费)_中间件常见问题-CSDN博客
前言:
我们知道深度学习一个重要特征是网络堆叠,深。 为什么需要深度,
本篇主要简单介绍一下该原因
目录:
1: 简介
2: 模块化分析
3: 语音识别例子
一 简介
有人通过实验,使用相同的网络参数,深度越深的网络相当于浅层网络效果更好。
1.1 Deeper is Better
如下图,随着网络层次逐渐加深,文本错误率逐渐降低
如下图,我们只用一层的网络,参数量跟多层一样,错误率高很多.
为什么产生这种现象?
同样的参数量,深度网络比浅层网络效果更好。
二 模块化分析
我们写程序,也把函数分为不同模块,实现不同功能
深度学习不同的层也相当于不同的函数,不同的函数实现不同的功能,
更高层也能使用到.
2.1 数据集的影响
比我我们要通过一个神经网络实现做4分类
长头发女生数据量大长头发男生数据量小短头发女生数据量大短头发男生数据量小 因为长头发男生数据集小,训练的网络一般会比较差。
解决方案:
使用更深层次的网络,有的用来识别男女,有的用来识别短头发长头发
然后更高层次的网络用来做4分类.
深度学习就相同于实现上面模组化的功能,每一层的神经元的输出,作为下一层神经元的输入.
我们没有足够的训练数据,所以做Deep Learning
三 语音识别例子 以发音识别为例:
输入了语音特征,输出对应的概率
在深度学习采样的模型如下:绿色模块是一些根据专家信息提取的声音
特征信息
Google 曾经做过实验:
使用深度学习的模型甚至完全不需要上面绿色的模块
可以达到前面模型一样的准确率.
11: Why Deep?_哔哩哔哩_bilibili
java语言中,给出了3种处理系统错误的机制:抛出一个异常、日志、使用断言。
1,异常 1)概念 当JAVA程序违反了JAVA的语义规则时,JAVA虚拟机就会将发生的错误表示为一个异常。
处理异常的一个重要原则是"只有在你知道如何处理的情况下才捕获异常"。实际上,异常处理的一个重要目标就是把错误处理的代码同错误发生的地点相分离。这使你能在一段代码中专注于要完成的事情,至于如何处理错误,则放在另一段代码中完成。这样一来,主干代码就不会与错误处理逻辑混在一起,也更容易理解和维护。通过允许一个处理程序去处理多个出错点,异常处理还使得错误处理代码的数量趋向于减少。
——《Think in java》
2)好的编码习惯 尽量不要捕获Exception 这样的通用异常,而是应该捕获特定异常。
首先,泛泛的 Exception 之类,隐藏了编码者的特定目的。其次,你可能更希望 RuntimeException 被扩散出来,而不是被捕获。最后进一步讲,除非深思熟虑了,否则不要捕获 Throwable 或者 Error,这样很难保证我们能够正确程序处理 OutOfMemoryError。不要生吞(swallow)异常。
基于假设我们可能判断某段代码可能不会发生,或者感觉忽略异常是无所谓的,直接吞掉异常不让其抛出来也不让它打印。程序可能在后续代码以不可控的方式结束,或者产生很诡异的问题。 2)场景 违反语义规则包括2种情况:
①JAVA类库内置的语义检查
例如数组下标越界,会引发IndexOutOfBoundsException;访问null的对象时会引发NullPointerException。
②JAVA允许程序员扩展这种语义检查,程序员可以创建自己的异常,并自由选择在何时用throw关键字引发异常。
所有的异常都是java.lang.Thowable的子类。
3)Throwable 4)Error与Exception区别 都是Throwable的子类。 ①Error 表示系统级的错误和程序不能处理的异常,表示故障发生于JVM,只有退出才可以处理。
举例:
ThreadDeath、Java.lang.OutOfMemoryError(内存空间不足)java.lang.StackOverFlowError(方法调用栈溢出)
通常「堆栈溢出」是指「调用堆栈(call stack)的溢出」。程序中一旦出现死循环或者是大量的递归调用,在不断的压栈过程中,造成栈容量超过默认大小而导致溢出。
栈溢出的原因:
递归调用层次太多
大量循环或死循环
全局变量过多
数组、List、map数据过大 系统崩溃 虚拟机错误 ②Exception Exception类表示程序可以处理的异常,可以捕获且可能恢复。一般是程序设计的不完善导致,分为RuntimeException和其它异常。
5)检查型异常和非检查型异常 ①检查异常(Checked) i>概念 编译器要求必须处理的异常。
如果不处理这类异常,程序将来肯定会出错。当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。
ii>包括:非运行时异常 即除了Error,RuntimeException及其子类以外,其他的Exception类及其子类都属于可查异常。
注意:.try{}catch{}会增加额外的开销。
iii>异常链 是Java中非常流行的异常处理概念,是指在进行一个异常处理时抛出了另外一个异常,由此产生了一个异常链条。
该技术大多用于将“ 受检查异常” ( checked exception)封装成为“非受检查异常”(unchecked exception)或者RuntimeException。顺便说一下,如果因为因为异常你决定抛出一个新的异常,你一定要包含原有的异常,这样,处理 程序才可以通过getCause()和initCause()方法来访问异常最终的根源。
②非检查型异常(Unchecked Exception) 编译器不要求处理的异常。
包括:运行时异常(RuntimeException与其子类)和错误(Error)。
例如:你的程序逻辑本身有问题,比如数组越界、访问null对象,这种错误你自己是可以避免的。编译器不会强制你检查这种异常。
6)Excetion分类 ①系统异常和普通异常 系统异常是软件本身缺陷所导致的问题,也就是软件开发人员考虑不周所导致的问题,软件使用者无法克服和恢复这种问题,但在这种问题下还可以让软件系统继续运行或者让软件死掉;
卷积神经网络 在前面的章节中,我们遇到过图像数据。这种数据的每个样本都由一个二维像素网格组成,每个像素可能是一个或者多个数值,取决于是黑白还是彩色图像。到目前为止,我们处理这类结构丰富的数据方式还不够有效。我们仅仅通过将数据展平成一维向量而忽略每个图象的空间结构信息,再将数据送入一个全连接的多层感知机中。因为这些网络特征元素的顺序是不变的,因此最优的结果是利用先验知识,即利用相近像素之间的互关联性,从图像数据中学习得到有效的模型。
本章介绍的卷积神经网络(convolutional neural network,CNN)是一类强大的、为处理图像数据而设计的神经网络。基于卷积神经网络架构的模型在计算机视觉领域中已经占主导地位,当今几乎所有的图像识别、目标检测或语义分割相关的学术竞赛和商业应用都以这种方法为基础。
现代卷积神经网络的设计得益于生物学、群论和一系列的补充实验。卷积神经网络需要的参数少于全连接架构的网络,而且卷积也很容易用GPU并行计算。因此卷积神经网络除了能够高效的采样从而获得精确的模型,还能够高效的计算。久而久之,从业人员越来越多地使用卷积神经网络。即使在通常使用循环神经网络的一维序列结构任务上(例如音频、文本和时间序列分析),卷积神经网络也越来越受欢迎。通过对卷积神经网络一些巧妙的调整,也是它们在图结构数据和推荐系统中发挥作用。
在本章的开始。我们将介绍构成所有卷积网络主干的基本元素。这包括卷积层本身、填充(padding)和步幅(stride)的基本细节、用于在相邻区域汇聚信息的汇聚层(pooling)、在每一层中多通道(channel)的使用,以及有关现代卷积网络架构的仔细讨论。在本章节的最后,我们将介绍一个完整的、可运行的LeNet模型:这是第一个成功应用的卷积神经网络,比现代深度学习的兴起时间还要早。在下一章中,我们将深入研究一些流行的、相对较新的卷积神经网络架构的完整实现,这些网络架构涵盖了现代从业者通常使用的大多数经典技术。
1.从全连接层到卷积 多层感知机十分适合处理表格数据,其中行对应样本,列对应特征。对于表格数据,寻找的模式可能涉及特征之间的交互,但是不能预设假设任何与特征交互相关的先验结构。此时,多层感知机可能是最好的选择,然而对于高维感知数据,这种缺少结构的网络可能会变的不实用。
不变性 卷积神经网络将空间不变性的概念系统化,从而基于这个模型使用较少的参数来学习有用的表示。
(空间不变性也就是在说换任何一个地方它本身都不会发生改变)
平移不变性:不管检测对象出现在图像中的哪个位置,神经网络的前面几层应该对相同的图像区域具有相似的反应,即为“平移不变性”。局部性:神经网络的前面几层应该只探索输入图像中的局部区域,而不过度在意图像中相隔较远区域的关系,这就是“局部性”原则。最终,可以聚合这些局部特征,以在整个图像级别进行预测。 多层感知机的限制 首先,多层感知机的输入是二维图像X,其隐藏特征H在数学上是一个矩阵,在代码中表示为二维张量。其中X和H具有相同的形状。为了方便理解,可以认为,无论是输入还是隐藏表示都拥有空间结构。
使用 [ X ] i , j [\mathbf{X}]_{i, j} [X]i,j和 [ H ] i , j [\mathbf{H}]_{i, j} [H]i,j分别表示输入图像和隐藏表示中位置 ( i , j ) (i,j) (i,j)处的像素。为了使每个隐藏神经元都能接收到每个输入像素的信息,我们将参数从权重矩阵(如同我们先前在多层感知机中所做的那样)替换为四阶权重张量W。假设U包含偏置参数,我们可以将全连接层形式化的表示为:
[ H ] i , j = [ U ] i , j + ∑ k ∑ l [ W ] i , j , k , l [ X ] k , l = [ U ] i , j + ∑ a ∑ b [ V ] i , j , a , b [ X ] i + a , j + b .
1、准备中文离线模型 配置文件夹
文件获取方法: 访问官网:https://huggingface.co/bert-base-chinese/tree/main
下载以下文件 2、测试代码 # -*- coding: utf-8 -*- #pip install transformers -i https://mirrors.aliyun.com/pypi/simple/ #pip install torch -i https://mirrors.aliyun.com/pypi/simple/ #pip install numpy -i https://mirrors.aliyun.com/pypi/simple/ #from transformers import AutoModel, AutoTokenizer from transformers import BertModel, BertTokenizer import torch import numpy as np # 加载预训练的中文BERT模型和分词器 # 这里手动下载模型与分词器,根据目录加载使用 vocab_file = 'model/vocab.txt' tokenizer = BertTokenizer(vocab_file) model = BertModel.from_pretrained("model/bert-base-chinese/") # 定义计算相似度的函数 def calc_similarity(s1, s2): # 对句子进行分词,并添加特殊标记 inputs = tokenizer([s1, s2], return_tensors='pt', padding=True, truncation=True) # 将输入传递给BERT模型,并获取输出 with torch.
好长没写博客了,学无止境,我倒是止步了。markdown也不会用了。好蠢,乘号都忘了转义。
因为密评涉及很多证书,我向来喜欢钻牛角尖,不想糊涂过去。
证书中,TLV解析的过程中,有个06的T,内容如下:
06 09 2A 86 48 86 F7 0D 01 01 0B
通过大众工具软件解析后是:
sha256RSA(1.2.840.113549.1.1.11)
思路:
一开始我肯定是按位去对,所以 01 01 0B没啥问题了。(这个没问题)
然后2A 的2进制是 00101010,因为我不懂真正的关系,我自以为是的认为是分成了2个4比特,然后前面有1个1,后面有2个1,所以解析结果(1.2)
实际上,(本次只阐述怎么算,不讲由来。)
1.2 => 1*40+2 => 42 = 2A
840 => 6*128+72 => 6+128=134,72 => 86 48
113549 => 6*128*128+119*128+13 => 6+128=134,119+128=247,13 => 86 f7 0D
本系列为作者学习UnityShader入门精要而作的笔记,内容将包括:
书本中句子照抄 + 个人批注项目源码一堆新手会犯的错误潜在的太监断更,有始无终 总之适用于同样开始学习Shader的同学们进行有取舍的参考。
文章目录 渲染流水线什么是流水线什么是渲染流水线应用阶段几何阶段光栅化阶段 CPU和GPU的通信把数据加载到显存设置渲染状态调用Draw Call 渲染流水线 什么是流水线 什么是流水线?书中举了一个生产洋娃娃的例子。一个洋娃娃的生成过程可以被分为4个步骤:
1. 制作躯干
2. 缝上眼睛和嘴巴
3. 添加头发
4. 最终包装
洋娃娃的制作经过了四道工序,如果每道工序耗时一小时。而一个工人想要生产一个洋娃娃则需要四个小时。资本家们想到了一个好方法,让每个专人负责一道工序,这样四个人四道工序,所有步骤就可以同时并行。假设工序1完成了洋娃娃A的躯干制作任务,那么他不需要等待洋娃娃A被最终包装就能直接进行下一个洋娃娃B的躯干制作任务了。
熟悉编程的小伙伴可能更了解它的另一个名字,就是PipeLine。例如很多程序都会封装一条Pipeline来自动化调用整条流水线。
那么显然,一个洋娃娃生产所耗费的最大时间将由其中最耗时的工序来决定。在了解了流水线的概念之后,我们来看看什么是渲染流水线?
什么是渲染流水线 实际上,计算机的图像渲染也是流水线工作,它的任务是由一个3D场景出发,渲染成屏幕显示的2D图像。这个工作常常是由GPU和CPU共同完成的。
根据书中的介绍,我们将整个渲染流水线分为三个阶段,分别为:
应用阶段(Application Stage)几何阶段(Geometry Stage)光栅化阶段(Rasterizer Stage) 其中每个阶段内部也包含了一些子流水线阶段。
应用阶段 这个阶段是由我们的应用主导的,并通常由CPU负责实现。我们开发者具有这个阶段的绝对控制权。
在这个阶段,我们需要做的工作有:
首先准备好场景数据,包括摄像机,视锥体,场景中的模型和光源等等。然后为了提高渲染性能,我们需要进行粗粒度剔除(Culling) 的工作,剔除不需要渲染的物体。最后,我们还需要设置好每个模型的渲染状态,包括但不限于其材质(漫反射颜色,高光反射颜色贴图)、纹理、使用的Shader等。(恰好部分内容在之前写的光照渲染笔记中粗略学习了) 这一阶段最终的输出是渲染所需的几何信息,即渲染图元(Rendering Primitives) ,通俗来讲,渲染图元可以是点,线,三角面(3d图形学中的面都是三角面构成的),这些渲染图元最终会被传入到下一个阶段——几何阶段
几何阶段 几何阶段通常在GPU上进行,用于和每个渲染图元打交道,决定绘制什么图元,怎样绘制它们,在哪里绘制。
几何阶段会进行逐顶点,逐多边形的操作,当然内部可以分为更小的流水线阶段。几何阶段的一个重要任务就是把顶点坐标变换到屏幕空间中,再交给光栅器进行处理。通过对输入的渲染图元进行多步处理后,这一阶段将会输出屏幕空间的二维顶点坐标信息、每个顶点对应的深度值、着色器Shader等相关信息、并传递给下一个阶段。
光栅化阶段 这一阶段将会使用上个阶段传递的数据来产生屏幕上的像素,并渲染出最终的图像,这一阶段也是再GPU上运行的。光栅化的任务最终决定每个渲染图元中的哪些像素应该被绘制再屏幕上,它需要对上一个阶段得到的逐顶点数据(例如纹理坐标UV,顶点颜色等)进行插值,然后进行逐像素的处理。同样的,光栅化阶段也可以分成更小的流水线阶段。
犹记得n月前初学Unity刚看到这些知识,看的云里雾里。现在再看,能够理解其中的流程,真是收获良多。
原作者注:
要把上面的3个流水线阶段和我们将要讲到的 GPU 流水线阶段区分开来;这里的流水线均是概念流水线,是我们为了给一个渲染流程进行基本的功能划分而提出来的(也就是渲染图像的三个主要阶段)。下面要介绍的 GPU 流水线, 则是硬件真正用于实现上述概念的流水线(也就是GPU的工作流程)。
CPU和GPU的通信 渲染流水线的起点是CPU,也就是之前提到的应用阶段。该阶段可大致分为下列3个阶段:
把数据加载到显存设置渲染状态调用Draw Call 把数据加载到显存 所有需要渲染的数据都是存储在硬盘(HDD)中的(例如模型的网格体,贴图纹理等数据),然后数据从硬盘被加载到系统缓存中(RAM),最终从系统缓存又被加载到显卡上的存储空间(Video RAM)。因为显卡对于RAM没有直接访问权限,而被加载到显卡的显存VRAM中则可以直接访问,并且显卡对于显存的访问速度显然更快。(为什么固态硬盘可以提高游戏渲染速度也是因为加快了数据从硬盘缓存到RAM的速度)
当然,真实加载到显存的数据要复杂得多,例如顶点位置信息,法线方向,顶点颜色,纹理坐标等等。
当数据被加载到显存后,显卡就可以访问了。那么RAM中的数据也可以被移除,不过某些数据依然需要CPU的访问(例如网格数据,我们需要CPU通过网格数据计算碰撞检测),那么这些数据是不会被移除的,因为数据从硬盘加载到RAM是十分耗时的。
此外,开发者还需要通过CPU设计渲染状态,来指导GPU的渲染工作。
设置渲染状态 渲染状态定义了场景中的网格是怎样被渲染的。例如使用哪些个顶点着色器(Vertex Shader)/片元着色器(Fragment Shader)、光源属性、材质等。这些都是我们可以在程序阶段进行自定义的:
(上图显示了使用同一种材质在不同渲染状态设置下最终渲染出的三个网格)
在准备好了上述工作后,CPU需要一个命令来通知GPU可以进行渲染了,这个渲染指令就是Draw Call
Android File Transfer是一款专为安卓设备设计的文件传输工具,可以帮助用户快速方便地在安卓设备和计算机之间传输文件。这款软件支持多种文件类型,包括图片、音乐、视频、文档等,使得用户可以轻松地将文件从计算机传输到安卓设备,或从安卓设备传输到计算机。
Android File Transfer具有简单易用的界面和操作方式,使用户能够轻松进行文件传输。用户可以通过USB连接将文件传输到安卓设备,也可以将文件从安卓设备传输到计算机。此外,该软件还提供了文件和文件夹管理功能,使用户可以轻松浏览设备的存储空间,创建、删除、重命名和移动文件和文件夹。
总的来说,Android File Transfer是一款功能强大、易于使用的文件传输工具,可以帮助用户快速方便地在安卓设备和计算机之间传输和管理文件。无论您是一名专业人士还是普通用户,Android File Transfer都是一个实用的工具,可以让您更加高效地管理您的文件。
安装:安卓文件传输工具---Android File Transfer中文
Android File Transfer是一款专为Mac用户设计的工具,用于在Mac电脑上方便地管理Android设备中的文件。以下是其主要功能特点:
简单易用:用户只需将安卓设备通过USB连接到计算机,然后启动该软件,即可开始传输文件。文件浏览和管理:用户可以在计算机上轻松访问安卓设备中的文件和文件夹。可以浏览设备的存储空间,包括内部存储和外部SD卡,查看、复制、剪切和粘贴文件,以及创建和管理文件夹。多种文件类型:支持传输多种文件类型,包括照片、视频、音乐、文档等。快速传输:可以快速地传输文件,不需要太长时间。大文件传输:支持传输大文件,可以满足用户的需求。兼容性:支持多种Android设备,包括三星、HTC、LG等品牌的设备。 使用方法如下:
下载安装:首先,您需要从官方网站或可信的第三方平台下载Android File Transfer的Mac版本安装包。然后双击安装程序并按照提示进行安装。根据您的操作系统,可能需要输入管理员密码以完成安装过程。连接设备:安装完成后,使用USB数据线将您的Android设备连接到Mac的USB端口。一旦设备连接成功,Android File Transfer将自动检测并显示一个窗口。浏览和传输文件:在Android File Transfer窗口中,您可以浏览Android设备上的文件和文件夹,并复制所需的文件到Mac电脑中,反之亦然。您还可以执行其他文件管理任务,如创建或删除文件夹。断开设备:完成文件传输或其他操作后,您可以断开Android设备与Mac的连接。 请注意,使用Android File Transfer时,确保您的Mac和Android设备都已开启USB调试模式,并且已授权计算机访问设备的存储空间。此外,定期更新Android File Transfer和您的操作系统可以确保最佳的性能和兼容性。
6. 学生成绩管理系统 视频教程:
【课程设计】学生成绩管理系统-JavaSwing -你的课程我设计 功能描述:
系统有管理员和教师两个角色,管理员登录之后可以进行课程管理、学生管理、排课;教师登录后可以进行评分;
学生管理包括查询、添加和修改。查询条件中的学院、系、班级是级联查询;添加学生时根据专业班级自动生成学号;学生信息添加成功后,只能修改备注;
课程列表可通过课程名模糊查询;课程分类包括专业选修、专业必修、公共选修、公共必修;
排课时选择班级、课程;一门课程可以有多个老师授课,但只能有一个老师评分;
教师登录后可以查看自己的课程;
只有评分老师能进行评分;
6.1 登录 输入用户名密码可以登录系统,用户名密码错误不能登录;
6.2 学生管理 管理员点击学生管理,将进入学生列表页;
可以根据学院、系、班级和学号进行查询,其中学院、系、班级为级联选择;
点击添加按钮打开添加学生页;
选择学院、专业、班级后自动计算出学号,学号规则为班级id+人数,如该班级已有2人,则当前学生为03号;
学生修改页面,只能修改备注;
6.3 课程管理 点击课程管理打开课程列表页,可根据课程名称进行模糊查询;
6.4 排课 点击排课菜单,打开排课计划页面,显示所有排课计划;
在排课计划页点击排课按钮,进行排课,排课页显示所有老师;
选择班级和课程,选中老师,点击排课,老师信息加入到下方授课老师列表中;
一门课程可以有多位授课老师,但只有一位老师可以设置为评分老师,点击设为评分按钮设置评分老师;
点击移除按钮可以移除已经选中的老师;
排课计划保存后不能修改,同一班级同一门课程不能重复安排;
6.5 评分 教师登录之后可以查看到自己的授课信息;
只有评分老师才能进行课程评分;
选中排课计划,进入评分页,评分页展示该排课计划对应班级的所有学生;
输入成绩后可以保存成绩;
必须输入所有学生的成绩才能保存;
22.数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
示例 1:
输入:n = 3
输出:[“((()))”,“(()())”,“(())()”,“()(())”,“()()()”]
示例 2:
输入:n = 1
输出:[“()”]
观察会发现,有效的组合在生成时一定满足左括号多余等于右括号,否则比如 ()) 无论之后怎么加括号最后都是无效组合,生成的过程不难想到用回溯法,在每一位尝试放左括号或者右括号,在前一步的基础上继续各自递归尝试,很像二叉树遍历,基本上套用回溯模版即可回溯模板 private void backtrack("原始参数") { //终止条件(递归必须要有终止条件) if ("终止条件") { //一些逻辑操作(可有可无,视情况而定) return; } for (int i = "for循环开始的参数"; i < "for循环结束的参数"; i++) { //一些逻辑操作(可有可无,视情况而定) //做出选择 //递归 backtrack("新的参数"); //一些逻辑操作(可有可无,视情况而定) //撤销选择 } } 最终代码 List<String> res = new ArrayList<>(); public List<String> generateParenthesis(int n) { dfs(n, n, ""); return res; } // left:能放的左括号数量,right 同理 // str:当前生成的字符串 public void dfs(int left, int right, String str){ // 说明此时右括号数量多余左括号,直接舍弃 if(left>right)return; // 左右括号都用完就记录该组合 if(left==0 && right == 0){ res.
组件树结构为Scaffold嵌套Scaffold时,在iOS有刘海屏的机型上,会出现子Scaffold顶部不响应点击事件的情况
页面结构如下:
整个页面是个Scaffold,红色框也是一个Scaffold,这时黄色框部分无法响应点击事件
一顿排查发现Scaffold会把顶部statusbar高度预留出来,这一部分高度无法点击
解决方式有三种:
1.在父组件外面套一层SafeArea
但这样顶部会有边距,不是我想要的
2.子组件不使用Scaffold
我这里需要Scaffold里的floatButton,所以这个方案我也没用
3.子组件Scaffold外层套一个MediaQuery.removePadding,把顶部空间移除掉
MediaQuery.removePadding( context: context, removeTop: true, child: Scaffold( backgroundColor: Colors.white, floatingActionButton: _floatingBtn(), body: _initSubviews(), ), )
之前有人问我 ,如果是二级路由如何添加,这里我做一个补充吧。直接拿方法去用就行。也不做解释了。稍微看下就能看懂了
假设,后端返回给我们一个数据 [“/defa”,"/defa/defa1"] 这样的一个路由表,我们就需要通过这个路由表去筛选匹配我们的动态路由,然后在进行添加。假设我们的动态路由是
[ { path: "/defa", name: "defa", component: () => import("@/views/DefaCat.vue"), children: [ { path: "/defa/fase1", name: "homelist1", component: () => import("@/views/UserZi.vue"), }, { path: "/defa/fase9", name: "homelist9", component: () => import("@/views/UserZi.vue"), }, ], }, { path: "/defa/fase2", name: "homelist2", component: () => import("@/views/UserZi.vue"), }, ]; 这样的一组数据,按照后端返回给我们的数据表,我们最终要拿到的数据是。
[ { path: "/defa", name: "defa", component: () => import("@/views/DefaCat.vue"), children: [ { path: "/defa/fase1", name: "homelist1", component: () => import("
🌹作者主页:青花锁 🌹简介:Java领域优质创作者🏆、Java微服务架构公号作者😄
🌹简历模板、学习资料、面试题库、技术互助
🌹文末获取联系方式 📝
系列专栏目录 [Java项目实战] 介绍Java组件安装、使用;手写框架等
[Aws服务器实战] Aws Linux服务器上操作nginx、git、JDK、Vue等
[Java微服务实战] Java 微服务实战,Spring Cloud Netflix套件、Spring Cloud Alibaba套件、Seata、gateway、shadingjdbc等实战操作 [Java基础篇] Java基础闲聊,已出HashMap、String、StringBuffer等源码分析,JVM分析,持续更新中 [Springboot篇] 从创建Springboot项目,到加载数据库、静态资源、输出RestFul接口、跨越问题解决到统一返回、全局异常处理、Swagger文档 [Spring MVC篇] 从创建Spring MVC项目,到加载数据库、静态资源、输出RestFul接口、跨越问题解决到统一返回 [华为云服务器实战] 华为云Linux服务器上操作nginx、git、JDK、Vue等,以及使用宝塔运维操作添加Html网页、部署Springboot项目/Vue项目等 [Java爬虫] 通过Java+Selenium+GoogleWebDriver 模拟真人网页操作爬取花瓣网图片、bing搜索图片等 [Vue实战] 讲解Vue3的安装、环境配置,基本语法、循环语句、生命周期、路由设置、组件、axios交互、Element-ui的使用等 [Spring] 讲解Spring(Bean)概念、IOC、AOP、集成jdbcTemplate/redis/事务等 前言 Apache ShardingSphere 是一款分布式的数据库生态系统, 可以将任意数据库转换为分布式数据库,并通过数据分片、弹性伸缩、加密等能力对原有数据库进行增强。
Apache ShardingSphere 设计哲学为 Database Plus,旨在构建异构数据库上层的标准和生态。 它关注如何充分合理地利用数据库的计算和存储能力,而并非实现一个全新的数据库。 它站在数据库的上层视角,关注它们之间的协作多于数据库自身。
1、ShardingSphere-JDBC ShardingSphere-JDBC 定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务。
1.1、应用场景 Apache ShardingSphere-JDBC 可以通过Java 和 YAML 这 2 种方式进行配置,开发者可根据场景选择适合的配置方式。
数据库读写分离数据库分表分库 1.2、原理 Sharding-JDBC中的路由结果是通过分片字段和分片方法来确定的,如果查询条件中有 id 字段的情况还好,查询将会落到某个具体的分片如果查询没有分片的字段,会向所有的db或者是表都会查询一遍,让后封装结果集给客户端。
题目描述 给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。
高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。
解题思路 分治法,取数组中间的值构建根节点数组左边的作为左子树,右边的作为右子树 代码实现 func sortedArrayToBST(nums []int) *TreeNode { if len(nums) <= 0 { return nil } mid := len(nums) / 2 root := &TreeNode{Val: nums[mid]} root.Left = sortedArrayToBST(nums[:mid]) root.Right = sortedArrayToBST(nums[mid+1:]) return root }
目录
一、问题描述
二、问题原因
三、解决方法
四、参考文章
一、问题描述 在启动Anaconda Prompt后,通过cd到项目文件夹启动Jupyter NoteBook点击.ipynb文件发生500报错。
二、问题原因 base环境下输入指令:
jupyter --version 发现jupyter环境下缺少安装包nbconvert。
三、解决方法 通过pip下载安装包,发现pip版本过低,要先升级。
由于下载安装包的权限设置,我的必须以管理员方式打开命令窗口才能升级。
输入指令:
python -m pip install --upgrade pip pip升级成功,下载缺失包nbconvert。
使用常规指令:
pip install nbconvert 发现不好使,环境中还是没有安装上。
更换指令:
pip install --upgrade --user nbconvert 安装成功。 看来是之前nbconvert版本过低导致。
之后就可以正常使用了。
四、参考文章 Jupyter notebook 报错 500 : Internal Server Error的解决方法「建议收藏」-腾讯云开发者社区-腾讯云jupyter notebook报错:500:Internal Server Error的解决方法_jupyter 500 : internal server error-CSDN博客
安装 nbconvert(转换jupyter notebook)-CSDN博客
python遇到问题_nbconvert指定下载源安装-CSDN博客
WEB漏洞-XSS跨站脚本漏洞解决方案-CSDN博客
Java使用过滤器防止XSS脚本注入_防注入 参数过滤-CSDN博客
春花秋月何时了,往事知多少。此付费专栏不要订阅,不要订阅,听人劝。
🌹作者主页:青花锁 🌹简介:Java领域优质创作者🏆、Java微服务架构公号作者😄
🌹简历模板、学习资料、面试题库、技术互助
🌹文末获取联系方式 📝
系列专栏目录 [Java项目实战] 介绍Java组件安装、使用;手写框架等
[Aws服务器实战] Aws Linux服务器上操作nginx、git、JDK、Vue等
[Java微服务实战] Java 微服务实战,Spring Cloud Netflix套件、Spring Cloud Alibaba套件、Seata、gateway、shadingjdbc等实战操作 [Java基础篇] Java基础闲聊,已出HashMap、String、StringBuffer等源码分析,JVM分析,持续更新中 [Springboot篇] 从创建Springboot项目,到加载数据库、静态资源、输出RestFul接口、跨越问题解决到统一返回、全局异常处理、Swagger文档 [Spring MVC篇] 从创建Spring MVC项目,到加载数据库、静态资源、输出RestFul接口、跨越问题解决到统一返回 [华为云服务器实战] 华为云Linux服务器上操作nginx、git、JDK、Vue等,以及使用宝塔运维操作添加Html网页、部署Springboot项目/Vue项目等 [Java爬虫] 通过Java+Selenium+GoogleWebDriver 模拟真人网页操作爬取花瓣网图片、bing搜索图片等 [Vue实战] 讲解Vue3的安装、环境配置,基本语法、循环语句、生命周期、路由设置、组件、axios交互、Element-ui的使用等 [Spring] 讲解Spring(Bean)概念、IOC、AOP、集成jdbcTemplate/redis/事务等 前言 在Chrome浏览器中,可以使用开发者工具的调试功能来调试和执行JavaScript代码。以下是一些常用的调试技巧:设置断点、单步执行、监视变量、控制台调试、异常处理。
这只是一些Chrome浏览器调试功能的例子。要打开开发者工具并访问调试功能,你可以按下Ctrl + Shift + J(Windows / Linux)或Command + Option + J(Mac),或者在浏览器菜单中选择"更多工具" > “开发者工具”,或者在页面上点击鼠标右键选中【检查】。在开发者工具的面板中,切换到"Sources"(或"代码")选项卡,即可访问调试功能。
在调试过程中,你可以在断点位置暂停代码执行、单步执行、检查变量值等。这有助于理解代码的执行流程和调试潜在的问题。
1、准备工作 1.1、创建html工程 使用Idea创建一个空工程 或者 其他编译器(vs , sublime , webStome)
1.2、创建html文件夹,存放html文件 1.3、创建JavaScript演示html <!DOCTYPE html> <html lang="en"> <head> <meta charset="
在vite.config.ts 增加下面配置
bypass(req, res, options: any) { const proxyURL = options.target + options.rewrite(req.url); console.log('proxyURL', proxyURL); req.headers['x-req-proxyURL'] = proxyURL; res.setHeader('x-req-proxyURL', proxyURL); // 设置响应头可以看到 } 控制台请求后会在 请求头里添加一个参数 X-Reg-Proxyurl,如下图
完整配置如下:
env.development
VITE_API_URL='/api/gateway/' vite.config.ts
import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; import vueJsx from '@vitejs/plugin-vue-jsx'; import path from 'path'; import { resolve } from 'path'; // https://vitejs.dev/config/ export default defineConfig({ server: { proxy: { '/api/gateway/': { target: 'http://192.168.0.66:8085', changeOrigin: true, rewrite: path => path.
解决方案 1. 检查node-sass安装版本是否正确。 本地安装的node版本不同,需要安装的node-sass版本也是不一样的。node-sass官方给出了不同版本的node和node-sass的对应关系,读者可访问node-sass github仓库或者node-sass npm仓库进行查看。 本地安装的node版本,可以使用如下命令进行查看:
node -v 在项目中还没有package.json或者有package.json但是此文件没有指定node-sass的版本时,默认会安装node-sass的最新版本。由于笔者安装的node版本时14.16.0,执行npm install node-sass命令默认安装了撰写本文时的node-sass最新版本8.0.0,所以才有了前文中报错。
根据版本对应关系,笔者应该安装node-sass的4.14+版本,因此需要将安装命令改为:
npm install node-sass@^4.14.0 --registry=https://registry.npm.taobao.org 这样就是使用淘宝源来安装node-sass的4.14+中的最新版本。
2. 检查是否是网络问题 在使用npm install安装node-sass时,会从 github.com 上下载 .node 文件。由于国内网络环境的问题,这个下载时间可能会很长,甚至导致超时失败。
附上报错截图。
这种情况下仅使用--registry参数指定npm包的下载源是不够的,还需要使用--sass_binary_site参数指定sass二进制文件的下载源,因此需要将安装命令改为:
npm install node-sass@^4.14.0 --registry=https://registry.npm.taobao.org --sass_binary_site=https://npm.taobao.org/mirrors/node-sass/ 这样一来就是指定node-sass版本,指定npm包下载源为淘宝源,指定sass下载源为淘宝源,使用此命令基本就都能安装成功了。
WEB标准颜色表_RGB颜色对照表_常用网页配色表_html安全色色卡_中英文色彩名称大全 - 桔子SEO (juziseo.com)
目录
一、OpenSSL创建自签名证书
1、下载安装OpenSSL
2、创建自签名的SSL证书和私钥
3、转换成.jks文件
二、配置Nginx
1、配置方法一:http和https同时监听,自动跳转https;
2、配置方法二:http自动跳转https;
3、配置方法三:http,https同时可访问;
三、开放443端口
一、OpenSSL创建自签名证书 1、下载安装OpenSSL 下载地址:https://www.openssl.org/source/
下载完成后上传到linux服务器上。
【安装OpenSSL】
tar -xzf openssl-1.1.1d.tar.gz cd openssl-1.1.1d mkdir /usr/local/openssl ./config --prefix=/usr/local/openssl make make install 【创建软连接】
which openssl #/usr/bin/openssl #为了使用方便,以及以后版本更新方便,可以创建软连接,如下: ln -s /usr/local/openssl/bin/openssl /usr/bin/openssl #如果报异常,可以忽略 【列出动态库依赖关系】
cd /usr/local/openssl ldd /usr/local/openssl/bin/openssl 【查看版本】
openssl version 2、创建自签名的SSL证书和私钥 【生产私钥(key文件)】
# -genra 生成RSA私钥 # -des3 des3算法 # -out server.key 生成的私钥文件名 # -2048 私钥长度 #输入一个4位以上的密码。 openssl genrsa -des3 -out server.pass.key 2048 【去除私钥中的密码】
openssl rsa -in server.
软件系统测试是指通过测试软件的安装、配置、集成和功能等多个方面,以验证系统是否符合预期需求并达到预期目标的过程。在测试过程中,我们会通过数据输入、操作触发、接口调用、异常处理等手段对软件系统进行全面检测。
一、软件系统测试的进行步骤
1、需求分析与测试计划:我们会仔细分析系统需求,制定详细的测试计划和测试策略,包括测试范围、测试目标、测试环境等。
2、测试设计与用例编写:根据测试计划,我们将设计测试用例,覆盖系统的各个功能模块和各种使用场景,并编写测试用例。
3、测试环境搭建:准备测试所需的硬件设备、操作系统、数据库等环境,并进行相应的配置和安装。
4、执行测试用例:按照测试计划,执行测试用例,记录测试结果,并及时跟踪和解决发现的问题。
5、问题验证与修复确认:对测试中发现的问题进行验证,并在修复后确认问题是否得到解决。
6、评估与报告:评估软件系统是否达到预期目标,并生成详细的测试报告。
二、软件系统测试的作用
1、帮助发现和解决软件系统的缺陷和问题,确保软件的质量和稳定性。
2、验证系统是否满足用户需求,以提供更好的用户体验。
3、减少软件开发和维护过程中的风险和成本。
4、提高软件交付的可靠性和可信度,增加用户信任度。
软件系统测试是保证软件质量和稳定性的重要环节。卓码软件测评,具备CMA、CNAS双重认证资质,拥有丰富的测试经验和专业的测试团队,各类测试类型全国范围内皆可服务,价格优惠,服务周到。
文章来源:软件系统测试怎么进行?对软件产品起到什么作用?—卓码软件测评
目录 注意事项一、2024/1/10更新前言一、YOLOv8推理(Python)1. YOLOv8预测2. YOLOv8预处理3. YOLOv8后处理4. YOLOv8推理 二、YOLOv8推理(C++)1. ONNX导出2. YOLOv8预处理3. YOLOv8后处理4. YOLOv8推理 三、YOLOv8部署1. 源码下载2. 环境配置2.1 配置CMakeLists.txt2.2 配置Makefile 3. ONNX导出4. 源码修改5. 运行 结语下载链接参考 注意事项 一、2024/1/10更新 修改第 4 部分 YOLOv8 推理中后处理 iou 计算代码,原代码存在问题,原代码如下:
def iou(box1, box2): def area_box(box): return (box[2] - box[0]) * (box[3] - box[1]) left, top = max(box1[:2], box2[:2]) right, bottom = min(box1[2:4], box2[2:4]) ... 其中,box1 和 box2 是表示边界框的列表,格式为 [left, top, right, bottom, …]。在 Python 中,当 max 函数用于两个列表时,它会比较列表中的元素,从左到右,直到找到某一个列表中的较大元素,然后返回那个较大元素的完整列表。比如现在比较 max([3,0],[2,1]),因为 3 大于 2,而不考虑后面的元素,返回的就是 [3,0]。这意味着在计算交集区域的左上角坐标时,仅比较了 left 坐标,而没有正确地处理 top 坐标,同理右下角坐标也存在类似的问题
在云计算日益普及的今天,无论是个人开发者还是企业用户,选择一款性价比高、性能稳定的云服务器显得尤为重要。阿里云作为国内领先的云服务提供商,近期推出了一系列令人心动的优惠活动,旨在让更多用户享受到高品质云服务带来的便捷和高效。
一、阿里云服务器购买多少钱一年?2024年最新阿里云活动价格汇总
此次优惠活动涵盖了多种配置的云服务器,满足不同用户的需求。以下是部分优惠信息的详细介绍:
轻量应用服务器:2核2G3M配置,仅需62元/年,适合轻量级应用和个人网站。经济型e实例云服务器ECS:2核2G3M配置,99元/年,性价比高,适合初创企业和个人开发者。通用算力型u1实例云服务器ECS:提供多种配置选择,其中2核4G版本706.25元/年,2核8G版本877.32元/年,4核8G版本1312.78元/年,4核16G版本1654.92元/年。通用算力型u1实例在性能、价格等方面表现均衡,是个人和企业的理想选择。 详情参考:
阿里云服务器优惠地址:https://aliyun.mian100.cn
腾讯云服务器优惠,2核4G5M服务器3年756元(推荐):https://tx.mian100.cn
腾讯云新用户先领券:https://xinke.mian100.cn
云产品续费贵,建议选择腾讯云那几款3年、5年时长的优惠服务器套餐;云产品升级贵,建议根据实际需求选配置高的。
二、阿里云服务器的优势
高性能:阿里云服务器采用先进的硬件设备和优化的系统架构,确保高性能输出,满足各种复杂应用场景。稳定性强:阿里云具备多年的云服务运营经验,服务器运行稳定,数据安全性高。弹性扩展:用户可根据业务需求灵活调整服务器配置,实现弹性扩展,降低成本。丰富的生态:阿里云提供全面的云服务解决方案,包括数据库、存储、网络等,满足用户一站式上云需求。 三、如何购买阿里云服务器?
想要抓住这次优惠机会的用户,可以通过以下链接直接访问阿里云服务器优惠购买页面:阿里云服务器优惠地址。在页面中选择合适的服务器配置和购买时长,按照提示完成购买操作即可。
四、总结
阿里云此次推出的服务器优惠活动力度空前,不仅有适用于个人和初创企业的经济型实例,还有满足中大型企业需求的通用算力型实例。无论您是个人开发者还是企业用户,都不要错过这次难得的优惠机会。赶紧行动吧!
文章目录 API文档环境配置API操作准备工作创建文件夹文件上传文件下载文件删除文件的更名和移动获取文件详细信息 API文档 HDFS API官方文档:https://hadoop.apache.org/docs/r3.3.1/api/index.html
环境配置 将Hadoop的Jar包解压到非中文路径(例如D:\hadoop\hadoop-2.7.2)
配置HADOOP_HOME环境变量
配置Path环境变量
API操作 准备工作 创建一个[Maven]工程HdfsClientDemo
引入hadoop-client依赖
<dependencies> <dependency> <grupId>org.apache.hadoop</groupId> <artifactId>hadoop-client</artifactId> <version>2.7.2</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.30</version> </dependency> </dependencies> 创建HdfsClient 类
创建文件夹 public class HdfsClient { //创建目录 @Test public void testMkdir() throws URISyntaxException, IOException, InterruptedException { //连接的集群nn地址 URI uri = new URI("hdfs://node1:8020"); //创建一个配置文件 Configuration configuration = new Configuration(); //用户 String user = "atguigu"; //1、获取到了客户端对象 FileSystem fileSystem = FileSystem.get(uri, configuration, user); //2、创建一个文件夹 fileSystem.
目录
一、Helm 基本使⽤
1.1 搜索 chart 应⽤ 1.2 部署 chart 应⽤ 1.3 删除 chart 应⽤
1.4 定制参数部署应⽤
1.5 chart 应⽤升级 1.6 chart 应⽤回滚 一、Helm 基本使⽤ 1.1 搜索 chart 应⽤ 使⽤ helm search repo 关键字可以查看相关 charts:
[root@k8s-master1 ~]# helm search repo nginx [root@k8s-master1 ~]# helm search repo mariadb 1.2 部署 chart 应⽤ 部署⼀个 MySQL 5.7 的应⽤(需要提前部署动态存储, nfs-provisionerstorage,参考文章 【云原生 | Kubernetes 实战】13、K8s 常见的存储方案及具体应用场景分析(下)-CSDN博客):
helm install stable/mysql --generate-name \ --set persistence.storageClass="nfs" \ --set mysqlRootPassword=Qwe123456 \ --set livenessProbe.
目录
一、Chart 基本介绍
1.1 什么是 Chart 1.2 Chart ⽬录结构 1.3 Chart.yaml ⽂件 二、创建不可配置 Chart 2.1 创建 Chart 2.2 安装 Chart 三、创建可配置的 Chart 3.1 修改 chart 3.2 安装 Chart 一、Chart 基本介绍 1.1 什么是 Chart Helm 部署的应⽤都是以 "chart" 包的形式存在的。每个 "chart" 包含了应⽤所有所需要的清单⽂件(诸如 Deployment、Service、Ingress、ConfigMap 等)。这些清单⽂件被保存为模板⽂件。当我们部署应⽤时,这些模板⽂件会被转化为 Kubernetes 资源清单⽂件。 1.2 Chart ⽬录结构 Helm Chart 的⽬录结构是预先定义好的。⽽每个 Chart 都应该⾄少包含 Chart.yaml ⽂件和 templates ⽬录。 [root@k8s-master1 ~]# helm create app [root@k8s-master1 ~]# tree app app ├── charts # 其他 Chart 的依赖,存储于此⽬录下。 ├── Chart.
目录 注意事项一、2024/1/10更新前言一、YOLOv8-Seg推理(Python)1. YOLOv8-Seg预测2. YOLOv8-Seg预处理3. YOLOv8-Seg后处理4. YOLOv8-Seg推理 二、YOLOv8-Seg推理(C++)1. ONNX导出2. YOLOv8-Seg预处理3. YOLOv8-Seg后处理4. YOLOv8-Seg推理 三、YOLOv8-Seg部署1. 源码下载2. 环境配置2.1 配置CMakeLists.txt2.2 配置Makefile 3. ONNX导出4. 源码修改 结语下载链接参考 注意事项 一、2024/1/10更新 修改第 4 部分 YOLOv8-Seg 推理中后处理 iou 计算代码,原代码存在问题,原代码如下:
def iou(box1, box2): def area_box(box): return (box[2] - box[0]) * (box[3] - box[1]) left, top = max(box1[:2], box2[:2]) right, bottom = min(box1[2:4], box2[2:4]) ... 其中,box1 和 box2 是表示边界框的列表,格式为 [left, top, right, bottom, …]。在 Python 中,当 max 函数用于两个列表时,它会比较列表中的元素,从左到右,直到找到某一个列表中的较大元素,然后返回那个较大元素的完整列表。比如现在比较 max([3,0],[2,1]),因为 3 大于 2,而不考虑后面的元素,返回的就是 [3,0]。这意味着在计算交集区域的左上角坐标时,仅比较了 left 坐标,而没有正确地处理 top 坐标,同理右下角坐标也存在类似的问题
只要我不努力,老板就永远也过不上他想要的生活
前言 今天我搭建项目的时候发现,使用MapStruct复制对象失败了,复制后所有的对象属性都为null。我一再检查,确信自己依赖没有引入错误,也没有什么特殊的配置,就是很简单的一个对象复制。
然后我就在网上查,网上找,都不尽如意。我之前搭的一个demo就一下子成功了,没有丝毫问题。于是我就把那个demo与这个项目比对一下,到底有什么区别,是什么导致那个demo能成功,这个项目就失败呢?
与Lombok有关系 终于让我发现了问题所在,大家可能觉得是不是lombok版本的问题?出乎我的意料,它不是版本问题,而是依赖引入的顺序问题。这怎么可能呢?我来来回回做了两遍实验,确认了这个事实。
将lombok的依赖放在它的上面就解决了这个问题
问题复现 首先我们复现一下问题,看以下代码是个很简单的对象拷贝,但是它的结果却是null
这是怎么回事呢?我们知道MapStruct会生成一个实现类,我们就看看这个实现类里的代码是怎么样的?
这就很奇怪了,怎么没有set get方法,lombok失效了吗?这个代码妥妥的都是null啊。于是我就跟之前的一个demo对比。尤其是pom文件,终于让我发现了华点。
我发现,lombok的顺序不一样,成功的demo在MapStruct上边,失败的本项目在MapStruct下边。当我想到这个的时候,我的第一反应是怎么可能呢?当然,有人可能会问为什么不是lombok版本的问题呢?关于版本问题我已经试过了,依然是失败的。
于是,我就没报什么希望,随便试一试,把lombok往前放,从最下面放在了最上面
然后再运行开头的那个方法,它竟然成功了。这就很神奇了。这个依赖的引入顺序怎么会影响它的编译呢?
希望遇到这个问题的同学,注意一下,很小的问题,但是很奇葩。
Package utils version 4.2.0
Usage read.table(file, header = FALSE, sep = "", quote = "\"'", dec = ".", numerals = c("allow.loss", "warn.loss", "no.loss"), row.names, col.names, as.is = !stringsAsFactors, na.strings = "NA", colClasses = NA, nrows = -1, skip = 0, check.names = TRUE, fill = !blank.lines.skip, strip.white = FALSE, blank.lines.skip = TRUE, comment.char = "#", allowEscapes = FALSE, flush = FALSE, stringsAsFactors = FALSE, fileEncoding = "", encoding = "
前言 官网:https://rockylinux.org/
阿里云:https://mirrors.aliyun.com/rockylinux
下载地址 最小镜像只有2G
https://mirrors.aliyun.com/rockylinux/8.8/isos/x86_64/Rocky-8.8-x86_64-minimal.iso?spm=a2c6h.25603864.0.0.234252d54FqxjJ
由于虚拟机没有对应的rockylinux,所以选其他
一 安装rockylinux,虚拟机安装 1 安装跟centos差不多 2 勾选启动时链接 二 最小化配置rockylinux 1 选择语言 2 配置磁盘 我这边只做了俩个分区
/ /boot
如果需要swap分区(1般是内存2倍)请自行添加
3 修改时间,Shanghai 4 软件安装 5 网络配置 [root@localhost ~]# cat /etc/sysconfig/network-scripts/ifcfg-ens33 TYPE=Ethernet PROXY_METHOD=none BROWSER_ONLY=no BOOTPROTO=static DEFROUTE=yes IPV4_FAILURE_FATAL=no IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no IPV6_ADDR_GEN_MODE=eui64 NAME=ens33 UUID=57ce9875-aaea-4609-8a84-364a9721ff09 DEVICE=ens33 ONBOOT=yes IPV6_PRIVACY="no" IPADDR="192.168.200.50" GATEWAY="192.168.200.250" NETWASK="255.255.255.0" DNS1="192.168.200.250" 重启网卡
nmcli c down ens33 && nmcli c up ens33 6 配置镜像源 除了上述两个镜像地址外,阿里云也提供了RockyLinux镜像
地址为:https://mirrors.aliyun.com/rockylinux/
官方配置 https://developer.aliyun.com/mirror/rockylinux/?spm=a2c6h.25603864.0.0.1ed31869hFU1IZ
文章目录 相关软件windows自带第三方软件 chfs(CuteHttpFileServer)下载软件GUI方案 补充命令行方案命令行程序定位简单创建服务站点使用配置文件配置细节 使用软连接或符号链接等手段将向共享站点的根目录添加文件开机自启服务包装nssm包装使用powershell包装 服务启动chfs服务@检查服务运行情况 效果附:模板配置 FAQ浏览器无法打开关于权限问题(访问控制)日志其他 相关软件 windows自带 IIS webdav windows自带的服务,启用相关功能后还要进行一系列的配置而且在WebDav客户端上传到站点的文件大小存在限制问题总体体验并不好,因此推荐第三方专业软件,灵活而且易于配置 第三方软件 CuteHttpFileServer | iscute.cn👺 提供了windos端的命令行程序和图形界面程序,轻量而且易于配置 GitHub - hacdias/webdav: Simple Go WebDAV server. 专门设计支持WebDav的命令行程序(可能停更了) Caddy - The Ultimate Server with Automatic HTTPS (caddyserver.com) candy+webdav:Module http.handlers.webdav - Caddy Documentation (caddyserver.com) chfs(CuteHttpFileServer) 本文介绍chfs的用法,该软件比较简单易用,轻量灵活(免费)几乎不用配置防火墙和共享站点的根目录的权限控制同时给出http和webdav的链接,用浏览器就可以进行webdav传输,享受webDav的优点浏览器所有设备几乎都有,因此可以不下在专门的客户端 下载软件 根据上述提供的官网,下载可执行文件 如果是计算机老手,可以考虑用命令行,更加轻量如果图方便或者是电脑新手,用GUI也是极好的(及其简单,可以将软件语言切换为中文,可以快速配置)复杂配置也建议用GUI比较方便 官网同时就是使用文档和使用说明书 GUI方案 支持语言切换和配置导出 软件启动:配置完成后,点击左上角的按钮切换服务启动或关闭状态
右上角可以切换语言和配置导出,观察操作日志
至此就可以实现方便的局域网内传输
补充 命令行方案 这里假设用户有命令行使用经验 windows比如cmd或者powershell都可以这里我用powershell 命令行程序定位 找到下载好的命令行可执行文件,比如D:\exes\chfs-windows-x64-3.1\chfs-windows-x64-3.1.exe
复制其所在目录,在命令行中定位到可执行文件
PS D:\exes\chfs-windows-x64-3.1> rvpa .\chfs-windows-x64-3.1.exe Path ---- D:\exes\chfs-windows-x64-3.1\chfs-windows-x64-3.1.exe PS D:\exes\chfs-windows-x64-3.1> sal chfs (rvpa .
一、命令行参数:
1、server.address=xxx.xxx.xx.xxx 服务器绑定ip地址,多网卡时可以指定
2、server.port=xxx 可以指定springboot内嵌容器启动的端口,默认使用tomcat容器时在8080端口,右键run- java application/springboot..,可以支持不同的容器,在引入不同的依赖时。当server.port=0时,表示自动扫面获取一个可用的端口。
3、ssl的安全访问配置:
server.port=8443 #ssl的安全访问配置 server.ssl.key-store=classpath:keystore.jks server.ssl.key-store-password=secret server.ssl.key-password=another-secret 注意: 目前spring-boot不支持http和https同时启用的情况,只支持使用其中一个,如果需要同时使用,可以使用其他形式的实现方式。
该部分对应org.springframework.boot.autoconfigure.webServerProperties类。
此外还有一些不是很常用的如:server.http2.enable=true/false//该属性可以支持http2的协议类型,目前只支持tomcat和undertow的容器并且需要JDK1.8+,官文上对于内嵌tomcat的配置参数也有很多。
二、开发/测试/生产环境配置:
1、语法:
spring.profiles.active=xxxx //该系统变量可以指明要使用的配置文件,一般应用于多环境配置分离,如生产环境(production),开发环境(development),测试环境(test)等,可以自定义,如开发环境配置文件为application-dev.properties,则spring.profiles.active=dev,在启动时会加载application-dev.properties配置文件。
2、使用方法:
(1)手动指定:这种方法切换环境需要修改配置文件,不够方便
spring.profiles.active = {profile} #如spring.profiles.active = prod (2)打包自动指定。
spring.profiles.active=@spring.profiles.active@ 3、demo:
启动类:
package com; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class ProfilesApplication { public static void main(String args[]){ SpringApplication.run(ProfilesApplication.class,args); } } 多环境配置文件:
开发环境application-dev.properties:
zt.profiles = this is dev 测试环境application-test.properties
zt.profiles = this is test 生产环境application-prod.properties zt.profiles = this is prod 接口:
效果图 代码 <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>登录</title> <style> *{ margin: 0; padding: 0; box-sizing: border-box; font-family: 'Poppins',sans-serif; } body{ overflow: hidden; } section{ display: flex; justify-content: center; align-items: center; min-height: 100vh; background: linear-gradient(to bottom,#f1f4f9,#dff1ff); } section .color{ position: absolute; filter: blur(150px); } section .color:nth-child(1){ top: -350px; width: 600px; height: 600px; background: #ff359b; } section .color:nth-child(2){ bottom: -150px; left: 100px; width: 500px; height: 500px; background: #fffd87; } section .
文章目录 简介Dockerfile内容基础知识DockerFile常用保留字指令FROMMAINTAINERRUNEXPOSEWORKDIRUSERENVADDCOPYVOLUMECMDENTRYPOINT 案例虚悬镜像 简介 Dockerfile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。
构建三步骤
1.编写Dockerfile文件 2.docker build命令构建镜像 3.docker run依镜像运行容器实例 Dockerfile内容基础知识 1:每条保留字指令都必须为大写字母且后面要跟随至少一个参数
2:指令按照从上到下,顺序执行
3:#表示注释
4:每条指令都会创建一个新的镜像层并对镜像进行提交
Docker执行Dockerfile的大致流程
(1)docker从基础镜像运行一个容器
(2)执行一条指令并对容器作出修改
(3)执行类似docker commit的操作提交一个新的镜像层
(4)docker再基于刚提交的镜像运行一个新容器
(5)执行dockerfile中的下一条指令直到所有指令都执行完成
从应用软件的角度来看,Dockerfile、Docker镜像与Docker容器分别代表软件的三个不同阶段,
Dockerfile是软件的原材料
Docker镜像是软件的交付品
Docker容器则可以认为是软件镜像的运行态,也即依照镜像运行的容器实例
Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石。
Dockerfile,需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西。Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等;
Docker镜像,在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行
Docker镜像时会真正开始提供服务;
Docker容器,容器是直接提供服务的。
DockerFile常用保留字指令 FROM 基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,第一条必须是from
MAINTAINER 镜像维护者的姓名和邮箱地址
RUN 容器构建时需要运行的命令
两种格式:
shell格式:
RUN yum -y install vim exec格式:
RUN是在 docker build时运行
EXPOSE 当前容器对外暴露出的端口
WORKDIR 指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点
USER 指定该镜像以什么样的用户去执行,如果都不指定,默认是root
ENV 用来在构建镜像过程中设置环境变量
ENV MY_PATH /usr/mytest
这个环境变量可以在后续的任何RUN指令中使用,这就如同在命令前面指定了环境变量前缀一样;
也可以在其它指令中直接使用这些环境变量,
比如:WORKDIR $MY_PATH
ADD 将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包
COPY 类似ADD,拷贝文件和目录到镜像中。
1 原理说明 这个方案有如下基本需求:
构建自定义CPUSET,/dev/cpuset中包含一个全新的cpuset分组。且可以通过set_cpuset_policy和set_sched_policy接口可以设置自定义CPUSET。开机启动后可以通过zygote判定来对特定的应用进程设置CPUSET,并一直保持,且保证自定义CPUSET不受其他CPUSET影响,持续独立。 原理上因为修改代码涉及部分较多,因此共分3个部分:
framework修改:添加SCHED GROUP和THREAD GROUP(THREAD_GROUP_对应SP_)的支持,且支持开机启动后直接设置。applyOomAdjLSP的判定保持不变。system修改:添加SP_CUSTOM的支持及set_cpuset_policy和set_sched_policy接口等支持,同时修改task_profiles.json,添加SP_CUSTOM CPUSET的支持。init.rc修改及编译部分调整:对自定义cpuset节点进行操作,vndk部分编译需要重新调整方案以及不修改VNDK如何保证编译通过。 由于修改中涉及代码量过大,这里拆分成两节进行展示。本章节主要针对第2部分和第3部分修改进行说明。上一篇文章👇
Android Framework 常见解决方案(25-1)定制CPUSET解决方案-framework部分修改
主要对第1部分修改进行说明。
2 修改方案(Android S) 2.1 system部分修改 针对system分区修改。具体修改方案如下(这里以S版本修改为主,Q和R有一些差异但原理不变):
在$AOSP/system/core/libprocessgroup/include/processgroup/sched_policy.h文件中修改:
/* Keep in sync with THREAD_GROUP_* in frameworks/base/core/java/android/os/Process.java */ typedef enum { SP_DEFAULT = -1, SP_BACKGROUND = 0, SP_FOREGROUND = 1, SP_SYSTEM = 2, SP_AUDIO_APP = 3, SP_AUDIO_SYS = 4, SP_TOP_APP = 5, SP_RT_APP = 6, SP_RESTRICTED = 7, + SP_CUSTOM = 8, SP_CNT, SP_MAX = SP_CNT - 1, SP_SYSTEM_DEFAULT = SP_FOREGROUND, } SchedPolicy; 这里注意,按照顺序填写修改相对简单,因为后续会用到SP_CNT和SP_MAX这两个变量,代码中还会有许多的遍历操作,因此最好采用累加方案,不要设置其他值。
import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D plt.rcParams["font.sans-serif"] = ["SimHei"]# 正确显示中文和负号 plt.rcParams["axes.unicode_minus"] = False # 创建数据 x = np.random.rand(50) y = np.random.rand(50) z = np.random.rand(50) # 创建第一个3D图形 fig = plt.figure(figsize=(12, 5)) ax1 = fig.add_subplot(121, projection='3d') ax1.scatter(x, y, z) ax1.set_title('第一个3D图') # 创建第二个3D图形 ax2 = fig.add_subplot(122, projection='3d',) ax2.scatter(x, -y, z) # 这里y取反以创建不同的图形 ax2.set_title('第二个3D图') # 显示图形 plt.show() 参考资料: python--matplotlib(4)_python matlab 库 plot_trisurf-CSDN博客https://blog.csdn.net/weixin_53197693/article/details/129156057
在本篇文章您将了解到两种生成正式签名的APK文件,当然还会了解到gradle build 与 gradle assemble的区别。
通过 Android Studio 生成使用 Gradle 生成 文章目录 前言使用Android Studio生成正式签名的APK文件使用Gradle生成正式签名的APK文件 前言 首先需要了解的是并不是所有的APK文件都能成功安装在手机上,能够安装在Android手机上的应用都是带有签名的。可能有小伙伴有疑惑了:为什么通过Android Studio运行生成的应用程序好像没有进行过签名啊?那是因为,Android Studio 使用了一个默认的 keystore文件帮我们自动进行了签名,可以在 Android Studio 中看到:
Gradle 面板——Tasks——android——signingReport,双击 signingReport,在控制台可以看到keystore 信息。
这就说明我们通过 Android Studio 运行的程序使用的都是这个 debug.keystore 文件来进行签名。
如果要想上架到应用商店,需要生成正式签名的 APK,那么问题来了,如何生成正式签名的APK 呢?本文将分享两种方法:
使用Android Studio生成正式签名的APK文件 点击 Android Studio 导航栏上的 Build——Generate signed APK ——选择APK——填写如下内容。如果没有 jks 文件的话,点击 Create new 即可生成新的。
其中 Validity(years)代表的是有效时长。具体信息可以添加如下内容
配置好信息之后,点击下一步选择release即可。
当点击Create后,右下角会有一个提示框:APK(s) generated successfully。当我们运行demo生成release版本时,该demo就是一个带有正式签名的APK文件。
使用Gradle生成正式签名的APK文件 在 testapp2 项目下的 build.gradle 文件中添加signingconfigs闭包,并在release闭包中使用。signingconfigs闭包中添加了一个config闭包,其中配置了keystore文件的各种信息,其中,storeFile 用于指定keystore文件的位置(文件必须已存在);storePassword用于指定密码,keyAlias用于指定别名,keyPassword用于指定别名密码。
android { namespace 'com.example.testapp2' compileSdk 34 defaultConfig { # 此处省略 } signingConfigs { config { storeFile file('/Users/zeng/zeng.
Kali Linux 白帽子必备操作系统,有时候重新安装又得折腾下,特此这里总结一下常见的命令,日后再配置的话就可以减少一些不必要的坑了,而且还可以帮助到一些网友,何乐而不为呢。
更新源 vim /etc/apt/sources.list 官方源 记住这个官方源就好了,不要被网上辣鸡文章误导,官方源会自动选择最近的源服务器更新的,简单明了。
deb http://http.kali.org/kali kali-rolling main non-free contrib deb-src http://http.kali.org/kali kali-rolling main non-free contrib ~如果你很无聊的话 可以手动尝试如下更新源~:不对,官方源有时候会抽风,自动选择的源速度慢的一匹。
中科大 deb http://mirrors.ustc.edu.cn/kali kali-rolling main non-free contrib deb-src http://mirrors.ustc.edu.cn/kali kali-rolling main non-free contrib 浙大 deb http://mirrors.zju.edu.cn/kali kali-rolling main contrib non-free deb-src http://mirrors.zju.edu.cn/kali kali-rolling main contrib non-free 东软大学 deb http://mirrors.neusoft.edu.cn/kali kali-rolling/main non-free contrib deb-src http://mirrors.neusoft.edu.cn/kali kali-rolling/main non-free contrib 解决安装进程占用 在 apt 安装软件的时候可能会出现以下问题:
无法获得锁 /var/lib/apt/lists/lock - open (11: 资源暂时不可用) 这是因为 apt 进程被占用了,解决方法也比较简单粗暴,直接删除掉 lock 锁文件即可:
给大家推荐免费的kugou音乐 vip哈, 还不知道的一定有相见恨晚的感觉,获取地址http://www.service99.cn
------------题记
每个框架都有查看权重参数的机制,在tenstensorflow中
查看的例子如下
import tensorflow as tf import numpy as np reader = tf.train.NewCheckpointReader('model-100') all_variables = reader.get_variable_to_shape_map() w0 = reader.get_tensor("conv0/W") print(type(w0)) print(w0.shape) print(w0[0]) b0 = reader.get_tensor("conv0/b") print(type(b0)) print(b0.shape) print(b0) 注意这里,在保存moxi模型的目录中有checkpoint文件,有model-100.data-00000-of-00001和model-100.index文件,此处我们只写.之前的东西。
直接是Numpy.ndarray格式,这个很好。
使用txt文件保存权重的代码为
import tensorflow as tf import numpy as np reader = tf.train.NewCheckpointReader('model-100') all_variables = reader.get_variable_to_shape_map() quantized_conv_list = ['conv1','conv2','conv3','conv4'] pf = open('result.txt', 'w+') for quantized_conv_name in quantized_conv_list: weight = reader.get_tensor(quantized_conv_name+"/W") print quantized_conv_name print '***************************************' print weight.shape [n,cout,h,w]=weight.
目录
权限管理的原则
常见的权限管理模型
总结
对企业而言,最重要的一个资源就是有价值的专有信息,也就是自己知道,而其他企业不知道的信息,因此,专有信息是企业的重要竞争力,权限管理的价值体现在专有信息的另个特点:专有信息价值的独占性和专有信息价值的时效性。
权限管理是系统设计必不可少的部分;好的权限管理能够有效提高系统的安全性,降低误操作,恶意破坏的风险,那么权限管理要遵循怎样的原则呢?
权限管理的原则 权限管理的核心只有一句话:员工获得的信息范围和细节程度,只要保证该员工职责的有效执行和落地即可;即最小特权原则
权限管理层级划分和逻辑权限管理分类 物理层级:办公场所、房间的权限,是否有访问某些档案的权限
逻辑层级:在信息网络、计算机上去访问数据的权限
功能权限管理分为3个颗粒度:模块级别、页面级别和接口级别
模块级别:由多个页面、接口功能组成,例如OA系统中,可以创建报销、发票等不同的流程
页面级别:每个页面会完成一项独立的任务;例如:查看报销流程申请进度的页面
接口级别:根据软件设计原则,一个接口仅完成一项任务,可以分为“增删改查”等4种不同的功能
常见的权限管理模型 访问控制列表ACL——Access Control List ACL模型是对每个资源分配一个列表,列表记录用户的访问权限
系统根据列表确定用户能否执行操作
最常使用在计算机网络中,路由器基于源ip地址进行过滤等
优点:实现简单
只需要一张列表,就可以记录每个用户对资源的访问权限
缺点:管理困难
难以规模化,资源数量增多,难以查询某个用户的所有权限
强制访问控制MAC——Mandatory Access Control 系统对用户和访问资源都标记安全等级,低安全等级的用户无法访问高安全等级的资源
使用场景一般是需要高等级保密的场所,如政府机构部门、军队等
在windows2008版本使用了MAC模型,系统中设置了5个安全等级
低等级,中等级,高等级,系统级,可信任级
优点:最为安全的一种保密措施,中心化的信息保密,数据等级只能由唯一的根管理员操作
缺点:维护成本高,需要定期维护数据等级;灵活性低,不利于组织协作,只能有一个管理员权限
自主访问控制模型DAC——Discretionary Access Control 用户对自身创建的资源拥有全部权限
拥有权限的用户,可以将该权限,授予其他用户,也可以收回授予的权限
使用场景:用户有权对所创建的对象进行访问
常用于文档系统的权限设计,例如微软的NTFS文件系统
在线文档的权限管理也常用DAC模型,大多在线文档都可以设置只读和编辑权限
优点:用户体验友好,符合人们的思维习惯;便于协作,可以传递权限给别的用户
缺点:安全最低的模型,数据容易泄露都按组织以外的人员;数据无法追溯,去中心的权限管理方式,无法记录数据使用历史;权限过于分散,不便于管理
角色访问控制模型RBAC——Role-based Access Control 基于组织中角色进行权限管理
不同角色赋予不同的访问权限
凡是存在角色分工的场景都可以使用,是目前使用最为广泛的模型
在windows系统中,用户组是典型的RBAC模型实现的
互联网公司常用的confluence wiki系统,退户权限也是基于RBAC实现
优点:灵活性高,通过管理角色来管理权限,仅修改角色权限记录;安全度适中,角色管理可以防止富裕用户多余权限,符合权限管理原则。较好的平衡了安全性和灵活性
缺点:搭建成本高,需要根据组织的角色进行权限设置;不试用临时授权;容易忘记临时授权操作,造成操作隐患
基于属性的访问控制模型ABAC——Attribute-based Access Control 被认为是下一代访问控制模型
访问用户与资源的关系是复杂的,可能基于多种不同的环境因素
基于多种不同环境属性,例如IP地址、时间、数据与访问者关系等,来决定是否允许操作
AWS亚马逊云服务的权限管理实现了ABAC的权限访问呢
优点:控制维度比较多,相比较RBAC,可以通过属性的方式添加控制维度;例如临时访客,可以增加时间标签,过期后自动销毁访问权限;安全程度高于RBAC;添加规则简单,创建新的属性即可
缺点:相比成本更高,相比于RBAC,需要定义的属性数量更多,工作量更大,不适用小型组织
总结: 模型名
模型介绍
通用场景
链接1: sudo:cmake:找不到命令
链接2: ubuntu下使用cmake报错No CMAKE_CXX_COMPILER could be found.的解决方法
链接3: could not find pythoninterp
链接4: 在Ubuntu上安装Boost的五种方法(全网最全,建议收藏)
链接5: Dependencies for required component LibUHD not met:
链接6: 解决Failed to load module canberra-gtk-module错误
链接7: USRP升级固件和FPGA镜像误
虚拟机ubuntu USB转网口连设备ping不通返回 destination host unreachable 虚拟机->可移动设备->连接对应的设备虚拟机->设备->USB控制器->USB兼容性:USB3.0查看设备防火墙,指令sudo ufw status,结果为不活动即可,否则输入sudo ufw disable在“USB以太网已连接”处设置ipv4可通过ifconfig查看网络情况
专栏集锦,大佬们可以收藏以备不时之需:
Spring Cloud 专栏:http://t.csdnimg.cn/WDmJ9
Python 专栏:http://t.csdnimg.cn/hMwPR
Redis 专栏:http://t.csdnimg.cn/Qq0Xc
TensorFlow 专栏:http://t.csdnimg.cn/SOien
Logback 专栏:http://t.csdnimg.cn/UejSC
量子计算:
量子计算 | 解密著名量子算法Shor算法和Grover算法
AI机器学习实战:
AI机器学习实战 | 使用 Python 和 scikit-learn 库进行情感分析
AI机器学习 | 基于librosa库和使用scikit-learn库中的分类器进行语音识别
Python实战:
Python实战 | 使用 Python 和 TensorFlow 构建卷积神经网络(CNN)进行人脸识别
Spring Cloud实战:
Spring Cloud实战 |分布式系统的流量控制、熔断降级组件Sentinel如何使用
Spring Cloud 实战 | 解密Feign底层原理,包含实战源码
Spring Cloud 实战 | 解密负载均衡Ribbon底层原理,包含实战源码
1024程序员节特辑文章:
1024程序员狂欢节特辑 | ELK+ 协同过滤算法构建个性化推荐引擎,智能实现“千人千面”
1024程序员节特辑 | 解密Spring Cloud Hystrix熔断提高系统的可用性和容错能力
1024程序员节特辑 | ELK+ 用户画像构建个性化推荐引擎,智能实现“千人千面”
1024程序员节特辑 | OKR VS KPI谁更合适?
使用方法:
<span style="cursor:auto">Auto</span> <span style="cursor:crosshair">Crosshair</span> <span style="cursor:default">Default</span> <span style="cursor:pointer">Pointer</span> <span style="cursor:move">Move</span> <span style="cursor:e-resize">e-resize</span> <span style="cursor:ne-resize">ne-resize</span> <span style="cursor:nw-resize">nw-resize</span> <span style="cursor:n-resize">n-resize</span> <span style="cursor:se-resize">se-resize</span> <span style="cursor:sw-resize">sw-resize</span> <span style="cursor:s-resize">s-resize</span> <span style="cursor:w-resize">w-resize</span> <span style="cursor:text">text</span> <span style="cursor:wait">wait</span> <span style="cursor:help">help</span>
题目分析:切蛋糕问题切记可以横着切,也可以竖着切。本题目需要快速求得两个矩形的和,可以用二维前缀和数组解决。然后枚举一刀切的位置。
#include <iostream> #include <algorithm> using namespace std; int a[1005][1005]; long long sum[1005][1005];/**< 注意到数据范围可能超过int */ int main() { int i,j,n,m; cin>>n>>m; for(i=1;i<=n;i++) for(j=1;j<=m;j++){ cin>>a[i][j];/**< 二维前缀和数组常见求法 */ sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j]; } long long ans=sum[n][m]; /**< 枚举蛋糕切割,注意可以横着也可以竖着切 */ for(i=1;i<n;i++) ans=min(ans,abs(sum[i][m]-(sum[n][m]-sum[i][m])));/**<sum[i][m]上半块蛋糕 */ for(j=1;j<m;j++) ans=min(ans,abs(sum[n][j]-(sum[n][m]-sum[n][j])));/**<sum[n][j]左半块蛋糕 */ cout<<ans; return 0; } 解释下:sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];作用
文章目录 Android 软键盘的显示和隐藏核心方法软键盘工具类点击空白区域隐藏软键盘方式一方式二 Android 软键盘的显示和隐藏 核心方法 显示软键盘:
InputMethodManager#showSoftInput(View view, int flags) 隐藏软键盘:
InputMethodManager#hideSoftInputFromWindow(IBinder windowToken, int flags) flags操作标志:
flags0SHOW_IMPLICITSHOW_FORCED0YYYHIDE_IMPLICIT_ONLYNYNHIDE_NOT_ALWAYSYYN 先弹出软键盘,再隐藏软键盘,Y 表示软键盘隐藏,N 表示软件不能隐藏。
SHOW_IMPLICIT:隐式弹窗键盘,表示弹出键盘不是由用户直接发起的,键盘可能不会弹出。
SHOW_FORCED:强制弹出键盘,表示弹出键盘是用户直接发起的,在用户请求收起键盘前,软键盘会一直显示。
HIDE_IMPLICIT_ONLY:只有通过 SHOW_IMPLICIT 弹出的键盘才能被隐藏。
HIDE_NOT_ALWAYS:表示只要不是通过 SHOW_FORCED 弹出的键盘都会被隐藏。
调用 SHOW_FORCED 可以保证软键盘一定会弹出,调用 0 可以保证软键盘一定会隐藏。
也可以简单粗暴的将两个方法中的 flag 都设为 0。
软键盘工具类 /** * 软键盘工具类 */ public class KeyboardUtils { /** * 显示软键盘 * * @param editText */ public static void showSoftInput(EditText editText) { if (editText == null) return; InputMethodManager imm = (InputMethodManager) BaseApplication.
笔者最近由于工作需要开始调研 Apache Doris,通过阅读聚合函数代码切入 Apache Doris 内核,同时也秉承着开源的精神,开发了 array_agg 函数并贡献给社区。笔者通过这篇文章记录下对源码的一些理解,同时也方便后面的新人更快速地上手源码开发。
聚合函数,顾名思义,即对一组数据执行聚合计算并返回结果的函数,在统计分析过程中属于最常见的函数之一,最典型的聚合函数包括 count、min、max、sum 等。基于聚合函数可以实现对大量数据的汇总计算,以更简洁的形式呈现数据并支持数据可视化。
相较于单机数据库,由于所有数据都存储在同一台机器上、无需跨节点的网络数据传输,往往单机数据库的聚合函数执行效率更高,而分布式数据库由于数据分散存储于多个节点、并行执行计算时需要从多个节点汇集数据,带来了额外的网络传输和本地磁盘 IO 开销,且多副本机制和分片策略也进一步增加了计算的数据量和管理的复杂性。
为避免单点瓶颈同时减少网络 IO,往往需要使用多阶段的方式进行执行,因此 Apache Doris 实现了灵活的多阶段聚合机制,能够根据查询语句的特点为其选择适当的聚合方式,从而在执行时间和执行开销(如内存,IO 等)之间取得有效的平衡。
多阶段聚合 在 Apache Doris 中,主要聚合机制有如下几种:
一阶段聚合:Group By 仅包含分桶列,不同 Tablet 的数据在不同的分组中,因此不同 BE 可以独立并行计算;
两阶段聚合:Group By 包含非分桶列,同一个分组中的数据可能分布在多个 BE 上;
三阶段聚合:Count Distinct 包含 Group By(即 2 个两阶段聚合的组合);
四阶段聚合:Count Distinct 不包含 Group by,通常采用 4 阶段聚合(1 个一阶段聚合和 1 个二阶段聚合的组合)
一阶段聚合 以如下查询为例,c1 是分桶列:
SELECT count(c1) FROM t1 GROUP BY c1 由于每个 BE 存储了若干个 Tablet ,每台 BE 只需要对当前节点上的 Tablet Set,分别进行 Hash Aggregate 即可,也称为 Final Hash Aggregate,随后对各个 BE 结果进行汇总。
@Configuration, @ConfigurationProperties, @EnableConfigurationProperties的功能 @Configuration是Spring的一个注解,作用就是说明这是一个bean,用于标记一个类为配置类,表示这个类中定义了一些配置信息,例如 bean 的定义、依赖关系等。通常,我们会在配置类中使用 @Bean 注解来定义 bean。配置类可以被 Spring 容器扫描到,并根据其中的配置信息来创建相应的 bean。配置类是 Spring Boot 中用于替代传统的 XML 配置文件的一种方式。
@ConfigurationProperties是 Spring Boot 提供的一个注解,用于将配置文件中的属性值绑定到一个 Java 对象上。使用 @ConfigurationProperties 注解,你可以创建一个 Java 类,并使用注解将其与配置文件中的属性进行绑定。在绑定过程中,Spring Boot 会自动将配置文件中对应的属性值赋给 Java 对象的相应字段或属性。
@EnableConfigurationProperties是 Spring Boot 提供的一个注解,用于启用 @ConfigurationProperties 注解的支持。在 Spring Boot 中,通过 @ConfigurationProperties 注解可以将配置文件中的属性值绑定到一个 Java 对象上。但是,默认情况下,这个绑定是需要手动进行的,即需要在配置类中使用 @EnableConfigurationProperties 注解来启用 @ConfigurationProperties 的支持。
使用注意事项
1、使用 @ConfigurationProperties时,从配置文件中读取的配置文件名称必须与java类中属性名称中保持一致才能从配置文件中读取数据映射到map,且在类中必须实现set方法。
2、@Configuration与@EnableConfigurationProperties不能同时使用,一起用就会出现重复创建同一bean的现象。会报错:expected single matching bean but found 2:xxxxxx。同理@Component与@EnableConfigurationProperties也不能同时使用。@Configuration与@Component关系见另一篇文章,Spring的@Configuration注解和@Component 注解的关系
文章目录 设置定时器声明FTimerHandle定义执行函数设置定时器 清除定时器 定时器(Timer) 可用于执行延迟类型的操作,或让某些操作在一段时间内重复执行。
设置定时器 定时器的设置只需三步即可完成:声明定时器句柄 FTimerHandle、定义执行函数、设置定时器,其中前两步是第三步的预备工作。
声明FTimerHandle 首先是声明定时器句柄 FTimerHandle,代码实现如下:
#include "TimerManager.h" UCLASS() class DEMO_API AMyCharacter : public ACharacter, public IMyInterface { GENERATED_BODY() public: // Sets default values for this character's properties AMyCharacter(); protected: // Called when the game starts or when spawned virtual void BeginPlay() override; public: // Called every frame virtual void Tick(float DeltaTime) override; // Called to bind functionality to input virtual void SetupPlayerInputComponent(class UInputComponent *PlayerInputComponent) override; //声明定时器变量 FTimerHandle TimerHandle; void TimerFunction(); }; 定义执行函数 void AMyCharacter::TimerFunction() { UE_LOG(LogTemp, Warning, TEXT("
插件和工具汇总 【一】MyBatis Log插件【二】热部署【三】一些快捷键 【一】MyBatis Log插件 能够自动拼接参数生成执行的SQL语句,可以更清晰看到执行本次接口调用的所有sql执行条数。在我们执行myabtis的时候,有的时候报错知道哪里错了,但是不知道具体的位置和参数,在使用Mybatis Log Plugin这个插件之后排查错误就很容易了。因为他可以把你的执行sql 脚本打印出来。之前那个打印sql日志,只是打印大概的模型,这个是打印具体的SQL脚本
(1)File–>Settings–>Plugins 搜索 MyBatis Log Plugin
(2)Installed安装之后重启,点击上方的Tools就能看到
(3)需要在配置文件添加如下配置:
(4)然后debug执行代码之后 点击启动MyBatis Log 插件 就可以查看每一步执行的sql
【二】热部署 【三】一些快捷键
场景:谷歌浏览器页面空白,并且点击设置没有反应
忘记我是在哪找的解决方案了,先留个记号在这,方便下次查阅
cadence SPB17.4 - allegro - CAM350_V10.7CN 引入槽孔(.rou)文件报错问题的优雅解决思路 Chapter1 cadence SPB17.4 - allegro - CAM350_V10.7CN 引入槽孔(.rou)文件报错问题的优雅解决思路概述现在用自己的思路去解决CAM350V10.7CN载入SPB17.4产生的槽孔文件出错的问题打开CAM14.6新建一个空工程引入实验目录的gerber文件集合CAM350V14.6导出gerber给CAM350V10.7CN用从主菜单上导出CAM350V14.6导出gerber数据CAM350V14.6导出槽孔数据关掉CAM350V14.6用CAM350V10.7CN载入CAM350V14.6导出的gerber试试 实验结论 Chapter1 cadence SPB17.4 - allegro - CAM350_V10.7CN 引入槽孔(.rou)文件报错问题的优雅解决思路 原文链接:https://blog.csdn.net/LostSpeed/article/details/126798730
概述 用cadence SPB17.4做完单板, 在cutout层画上拼板框, 摆上拼板工艺边上的4个定位孔和3个mark点.
摆上钻孔表, 导出钻孔文件和槽孔文件. 出全套gerber文件.
反复确认过, 在SPB17.4这边, 做的步骤都对.
用CAM350_V10.7CN引入SPB17.4导出的gerber文件, 准备编辑单板为拼板.
但是CAM350导入.rou时就报错了, 导致导入后, 槽孔层没内容.
去查了资料, 大家的通常处理都是编辑.rou文件, 去掉文件开头几行处的%字符以上的所有内容.
但是这种方法, 会将槽孔钻头的数据搞掉. 导致所有槽孔钻头都统一使用93mil的钻头.
还有老手会在载入.rou后, 忽略错误, 然后自己用NC编辑器手工指定多个槽孔钻头尺寸.
如果只是普通研发, 不是板厂的同学(人家专门玩CAM), 这个很难办.
换个思路来解决这个问题
板厂检查提交的gerber文件是否合规, 是用CAM350V10来检查的.
所以, 最终拼板用的软件一定要用CAM350V10. 而不是用其他版本的CAM软件来拼板.
用高版本的CAM350_V14.6软件引入SPB17.4导出的gerber, 这时是正常引入, 然后导出gerber数据, 钻孔数据, 槽孔数据.
再用CAM350_V10.7CN打开CAM350_V14.6导出的数据, 这时就能正常载入了(这说明SPB17.4生成的槽孔文件是高版本CAM350才能支持的, 高版本CAM350导出的槽孔文件考虑了兼容性, 会被低版本的CAM350识别), 然后在CAM350_V10.7CN中进行手工拼板操作, 输出为最终给板厂的gerber文件.
Apache common提供了很多实用的工具包,下面就说一下如何用compress包来压缩文件夹。先引入compress,io和lang3这3个工具包:
<dependencies> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-compress</artifactId> <version>1.9</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.8</version> </dependency> </dependencies> 这个方法实现了将文件夹下所有的文件压缩成zip包,并输出到文件流中,可以直接写入到文件或提供给前端下载,工具类如下:
import org.apache.commons.compress.archivers.ArchiveException; import org.apache.commons.compress.archivers.ArchiveStreamFactory; import org.apache.commons.compress.archivers.zip.Zip64Mode; import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.io.filefilter.TrueFileFilter; import org.apache.commons.lang3.StringUtils; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Collection; public class ZipUtils { /** * 压缩文件夹下的所有文件 * @param dir 要压缩的文件夹 * @param outputStream 输出压缩后的文件流 * @throws IOException IO异常 * @throws ArchiveException 压缩异常 */ public static void zip(File dir, OutputStream outputStream) throws IOException, ArchiveException { ZipArchiveOutputStream zipOutput = null; try { zipOutput = (ZipArchiveOutputStream) new ArchiveStreamFactory() .
kmalloc、kzalloc、vmalloc的区别 我们都知道在用户空间动态申请内存用的函数是 malloc(),这个函数在各种操作系统上的使用是一致的,对应的用户空间内存释放函数是 free()。注意:动态申请的内存使用完后必须要释放,否则会造成内存泄漏,如果内存泄漏发生在内核空间,则会造成系统崩溃。
那么,在内核空间中如何申请内存呢?一般我们会用到 kmalloc()、kzalloc()、vmalloc() 等,下面我们介绍一下这些函数的使用以及它们之间的区别。
kmalloc 函数原型:
void *kmalloc(size_t size, gfp_t flags); kmalloc() 申请的内存位于物理内存映射区域,而且在物理上也是连续的,它们与真实的物理地址只有一个固定的偏移,因为存在较简单的转换关系,所以对申请的内存大小有限制,不能超过128KB。
较常用的 flags(分配内存的方法):
GFP_ATOMIC — 分配内存的过程是一个原子过程,分配内存的过程不会被(高优先级进程或中断)打断;
GFP_KERNEL — 正常分配内存;
GFP_DMA —给 DMA 控制器分配内存,需要使用该标志(DMA要求分配虚拟地址和物理地址连续);
flags 的参考用法:
进程上下文,可以睡眠:GFP_KERNEL进程上下文,不可以睡眠:GFP_ATOMIC 中断处理程序:GFP_ATOMIC软中断:GFP_ATOMICTasklet:GFP_ATOMIC 用于DMA的内存,可以睡眠:GFP_DMA | GFP_KERNEL用于DMA的内存,不可以睡眠:GFP_DMA |GFP_ATOMIC 对应的内存释放函数为:
void kfree(const void *objp); kzalloc kzalloc() 函数与 kmalloc() 非常相似,参数及返回值是一样的,可以说是前者是后者的一个变种,因为 kzalloc() 实际上只是额外附加了 __GFP_ZERO 标志。所以它除了申请内核内存外,还会对申请到的内存内容清零。
static inline void *kzalloc(size_t size, gfp_t flags) { return kmalloc(size, flags | __GFP_ZERO); } kzalloc() 对应的内存释放函数也是 kfree()。
vmalloc 函数原型:
文章目录 前言一、定义类继承Popup类二、使用1.在XAML头部加入链接2. 在XAML文件使用 总结 前言 由于WPF 默认的Popup总是显示在所有窗口的前面,如何让popup 层只显示在该父级之上,并随着父级而动呢?下面来看实现。
一、定义类继承Popup类 public class PopupEx : Popup { /// <summary> /// 是否窗口随动,默认为随动(true) /// </summary> public bool IsPositionUpdate { get { return (bool)GetValue(IsPositionUpdateProperty); } set { SetValue(IsPositionUpdateProperty, value); } } public static readonly DependencyProperty IsPositionUpdateProperty = DependencyProperty.Register("IsPositionUpdate", typeof(bool), typeof(PopupEx), new PropertyMetadata(true, new PropertyChangedCallback(IsPositionUpdateChanged))); private static void IsPositionUpdateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as PopupEx).pup_Loaded(d as PopupEx, null); } /// <summary> /// 加载窗口随动事件 /// </summary> public PopupEx() { this.
系统架构设计:如何根据业务需求和技术要求进行系统架构设计?
技术选型与评估:如何选择合适的技术栈和工具,并进行技术评估和风险分析?
模块划分与解耦:如何合理划分系统模块,降低模块间的耦合度,提高可维护性和可扩展性?
数据架构设计:如何设计数据架构,包括数据模型、数据存储、数据流程等?
系统性能优化:如何优化系统性能,提高系统吞吐量和响应速度?
系统安全性设计:如何设计系统安全机制,确保系统的安全性、可靠性和稳定性?
系统可维护性考虑:如何考虑系统的可维护性,降低维护成本和提高系统的可用性?
架构评审与改进:如何定期进行架构评审,发现存在的问题并进行改进?
跨部门沟通与协作:如何与其他部门沟通协作,确保系统架构设计与业务需求的一致性?
持续学习与技术跟踪:如何持续学习新技术和跟踪行业发展趋势,提高自己的技术水平?
Mixtral 8x7B 的推出在开放 AI 领域引发了广泛关注,特别是混合专家(Mixture-of-Experts:MoEs)这一概念被大家所认知。混合专家(MoE)概念是协作智能的象征,体现了“整体大于部分之和”的说法。MoE模型汇集了各种专家模型的优势,以提供更好的预测。它是围绕一个门控网络和一组专家网络构建的,每个专家网络都擅长特定任务的不同方面
在本文中,我将使用Pytorch来实现一个MoE模型。在具体代码之前,让我们先简单介绍一下混合专家的体系结构。
MoE架构 MoE由两种类型的网络组成:(1)专家网络和(2)门控网络。
专家网络:专家网络是专有模型,每个模型都经过训练,在数据的一个子集中表现出色。MoE的理念是拥有多名优势互补的专家,确保对问题空间的全面覆盖。
门控网络:门控网络充当指挥,协调或管理个别专家的贡献。它学习(或权衡)哪个网络擅长处理哪种类型的输入。经过训练的门控网络可以评估新的输入向量,并根据专家的熟练程度将处理责任分配给最合适的专家或专家组合。门控网络根据专家的输出与当前输入的相关性动态调整其权重,确保定制响应。
上图显示了MoE中的处理流程。混合专家模型的优点在于它的简单。通过学习复杂的问题空间以及专家在解决问题时的反应,MoE模型有助于产生比单个专家更好的解决方案。门控网络作为一个有效的管理者,评估情景并将任务传递给最佳专家。当新数据输入时,模型可以通过重新评估专家对新输入的优势来适应,从而产生灵活的学习方法。
MoE为部署机器学习模型提供了巨大的好处。以下是两个显著的好处。
MoE的核心优势在于其专家网络的多元化和专业化。MoE的设置能够以单一模型可能难以达到的精度处理多方面的问题。
MoE具有固有的可伸缩性。随着任务复杂性的增加,可以在不改变其他专家模型的情况下将更多专家无缝地集成到系统中,扩大专业知识的范围。也就是说,MoE可以帮助将预先训练过的专家打包到机器学习系统中。
混合专家模型在许多领域都有应用,包括推荐系统、语言建模和各种复杂的预测任务。有传言称,GPT-4是由多个专家组成的。尽管我们无法确认,但类似gpt -4的模型将通过MoE方法利用多个模型的力量来提供最佳结果。
Pytorch代码 我们这里不讨论Mixtral 8x7B这种大模型中使用的MOE技术,而是我们编写一个简单的、可以应用在任何任务中的自定义MOE,通过代码我们可以了解MOE的工作原理,这样对理解MOE在大模型中的工作方式是非常有帮助的。
下面我们将一段一段地介绍PyTorch的代码实现。
导入库:
import torch import torch.nn as nn import torch.optim as optim 定义专家模型:
classExpert(nn.Module): def__init__(self, input_dim, hidden_dim, output_dim): super(Expert, self).__init__() self.layer1=nn.Linear(input_dim, hidden_dim) self.layer2=nn.Linear(hidden_dim, output_dim) defforward(self, x): x=torch.relu(self.layer1(x)) returntorch.softmax(self.layer2(x), dim=1) 这里我们定义了一个简单的专家模型,可以看到它是一个2层的mlp,使用了relu激活,最后使用softmax输出分类概率。
定义门控模型:
# Define the gating model classGating(nn.Module): def__init__(self, input_dim, num_experts, dropout_rate=0.1): super(Gating, self).__init__() # Layers self.layer1=nn.Linear(input_dim, 128) self.dropout1=nn.Dropout(dropout_rate) self.layer2=nn.Linear(128, 256) self.
JQuery异步加载表格选择记录 JQuery操作表格 首先在页面中定义一个表格对象
<table id="insts" class="table"> <thead> <tr> <th>列1</th> <th>列2</th> <th>例3</th> <th></th> </tr> </thead> <tbody> </tbody> </table> 其中<tbody>中数据为空,当加载数据时,需要往里填充数据。
另外在页面中加入下面标签用以触发响应。
<button id="btnSearch">查找</button> 在页面初始化的处理函数中加入下面代码用以响应。
<script type="text/javascript"> $(function () { $("#btnSearch").button().on("click", function(){ }); JQuery操作表格的方法
清空表格内的数据 $("#insts tbody").empty(); 加载表格数据 $("#insts tbody").append("<tr><td>" + details + "</td><td>" + item["assLangName"] + "</td><td>" + sel + "</td></tr>"); 其中details, item["assLangName"]和sel是要填充的数据。
异步加载 异步加载使用JQuery提供的getJSON方法,利用JSON对象可以方便的填充数据。其中item["assLangName"]是JSON数组中某一子项中的assLangName成员。
假设从服务端传过来的成员对象如下
var instLink = 远程链接地址; $.getJSON(instLink, function (data) { $.each(data, function (i, item) { var details = 数据1; var sel = 数据2; $("
当2023年过去,该如何回味?年龄又长了一岁,是第32岁。工作又多了一年,是毕业的第9年。生活多了些品质,买车且提前还清了房贷。家中增添了一份子,是全家的期盼。
前者是时间为众生留下的轨迹交互,后者是岁月在自我的独特留痕。我们处理好了自己的留痕,也就处理好了与周遭一切的交互。
2023年,做了一些事情,有了一些感触。这一年在工作、生活等多个角度,都留下了一些重要片段。
01
工作
工作不是一份朝九晚五或996或摸鱼内卷的形式主义,是应当有价值、有产出、有收获的实事求是。
23年我的工作内容变化很大,围绕着做事,彻底抛开产品边界去拥抱业务,外部更多的深入一线调研,内部开始考虑机制设计与团队配合。
1 证明存在的合理性
在现在的大环境下,不证明自己的价值就没有存在的必要。必须先获得世俗的商业价值的成功,才有持续性的可能。在商业化上做的好,才是真正的对用户对团队负责。
23年我在保留对体验初心的情况下,完成了商业化的提升。一昧的讲究情怀没有意义,产品经理的初心需要一定的底气支撑。面向自己的产品用户,我能扪心自问的说句问心无愧。
就像小时候没写完作业会挨打一样,你不能揪着父母的打骂说他们不爱你,他们正是因为爱你才会在没达成预期目标时(比如没写作业)有所行动(打骂)。
先证明存在的合理性,再追求体验的初心。在没有1的情况下,再多的0都毫无价值。
在入不敷出的项目里面,就得拼命奔跑。如果不拼命地向前跑,可能人就不是这些人,项目就会进入到关停并转的阶段。
也许激进的无所顾忌会招来用户的骂名和同事的不理解,但事后再来看这些情感上的应激反应,没那么重要。
我不提供情绪价值,我提供的是完成目标的勇气。
2 面向客户和同事
23年我把大量的精力放在了B端,相应的就需要不断的跑客户做调研,以至于现在基本做到了随时随地的办公、开会、过项目。
做SAAS类服务,深入一线才能得到客户的真实反馈,找到产品在宣传上、功能上的重点,把这些包装成销售团队能理解的话术和方案,才能在销售业绩上体现出来。
除了广州、杭州的大本营,今年的出差我去了上海、南京、宁波、深圳、汕头、中山、佛山,有时候连续的中转,一周内会出现三种季节的变换。
(23年平均两周飞一次)
从北京的后厂村到杭州的滨江再到广州的华观路,往返停留这三地,在工作上面向不同的办公地、不同的职能团队、不同风格的同事,在接触中流连的是城市的差异、潮涌的人流和奋斗的预期。
过程中我是参与者,团结各部同事为了同一个业绩目标而努力,跟销售策划讨论定价机制和提成奖励,为销售团队做培训和答疑,与市场运营策划直播宣讲和制定投流方案。我以一种开放的心态参与,推进整个项目的进展。
过程中我是旁观者,我深刻的明白如果离开这些职能我将做不成任何事情,我要站在共创的角度去探索做事的合理性,让每种职能都能发挥其应有的甚至超出本身的价值。
我开始看人,看实体小老板的处事风格和关切问题,基于此调整销售的话术和演示功能的侧重点。开始看同事的习惯和处事逻辑,尽可能的调整频率进去到他们的频道,来达到尽可能多的共情。
我始终认为我个人相对纯粹,没有对事情和个人的喜恶,别人不需要为我提供任何的情绪价值,我只是想把事情给做了。但既然事情需要深入一线,那就按照一线的处理逻辑来进行,我没任何异议且能把它做好。
3 摒弃自我又重拾自我
我是一个极具判断的人,对事物有自己的看法。任何的结论输入,我都会用我自己的逻辑再推演一遍。这是我的底层处事之道。
同时,我又认为事情不止一种角度,解法也有很多种。重要的不是证明我是对的,而是达成一致并开始执行验证(打工人的自觉),所以我决策的时候,我会相信我的判断。不是我决策的时候,我会觉得你说的也有道理。
但在这点上,我今年吃了几次不小的亏,让我开始重新思考处事的逻辑。
在面向外部做SAAS需求时,我会继续沿用我的判断,直接下结论认为客户需要或者不需要,我甚至有一种无需调研的盲信。但我忽略了我的信息量不够,无法还原客户的场景和习惯,造成了支撑销售业绩出现了偏差。
在面向内部的机制设计时,我会沿用我的习惯可以面向海量信息抓住重点和有序递进。但我忽略了人不一样,对事物的接受程度也不一样。是人的差异,造成了结果的差异。我逻辑严密的流程设计,不接地气。
在23年7-8月的低谷,我开始有点怀疑我自己。我变的有点畏手畏脚,不敢出结论、不敢下判断。我开始往上述第二条的处事逻辑倾斜,认为老板说得对、客户说得对、同事说得对。我放飞了自我。
但这个过程我很纠结,问题出在了哪里?
Q4我终于想明白,我的问题的核心是信息量,我不够了解客户,我的已知是只是局部,不能回答客户全部的问题。
我忽略了人和团队的配合和积极性调动。我惯用的仅站在做事的角度梳理流程是不够的,还应该考虑人在其中的作用——用现在的人,把事做了。
我终于把我自己拼凑完整,可以继续的相信自己的判断,基于充分获取信息后的谨慎决策。
02
生活
工作是期待美好的底气,生活正是期待的美好本身。23年初我在规划里给自己定了三个目标:买车、还贷、生二胎,目标进度3/3,全部完成。
1 买车,给自己的礼物
年初我买了唐DMp,满足了我对车的所有想象。配置拉满,百公里加速4.3秒,油电切换没有焦虑,座椅可以在五座和七座之间随意切换。
大学毕业我就期待着买车,但因为北京的限牌政策而人又不在老家,所以一直纠结于买和不买。
22春节年我终于下定了决心,盲订了汉DMi。在新车上市之后唐DMp让我欣喜若狂,于是在交了一年的定金之后终于拿下。
(我的梦中情车)
作为有娃的父亲角色,需要一辆车来承载家庭的诉求。娃在哪车就应该在哪,至于开的多或少,我已不再纠结因为一点也不重要。
有车就有诗和远方。独自开车的时候,来一脚油门体验推背感。遛娃的时候,说走就走体验风和自由。我是如此的热爱生活。
2 还贷,不负债
今年我成形了自己的金融观:不负债。
不负债的观念是如此明确,以至于我把以后买房的红线直接定在了不超过资产的70%。不仅不能负债,还要有一定的结余。
17年买了一套小房子,还有几十万的贷款在慢慢还。在提前还贷的风潮和自己不负债的新思想下,说啥都得提前换了。于是排队预约,按期换上,打完收工。
生活没有容错空间,君子不立于危墙之下。有多大屁股,穿多大裤衩。现在已有太多的不确定,不负债就是我应对不确定的处事逻辑。
想拥有美好的生活,就先拥有足够的资本。我乐观的期望着生活,用不负债来兜底自己的随遇而安。
3 二胎,儿女双全
二胎出生的时间在23年底,刚足月就迫不及待的见面,相比预产期提前了2周多。
我期待孩子们的成长,期望后续有更多的陪伴,希望能有所成绩给他们更多的支撑,这是我在32岁年纪的又一动力。
03
公众号
23年的公众号基本处于停滞状态,原因是没想好写的内容。
上半年非常明确不写产品经理相关的内容,下半年理清楚思路后写的内容始终过不了自己这关,于是笔记本里的内容写写删删的草稿有几十篇。
公众号肯定要持续写,保持思考是必要的。公众号的定位本是表达,当经历/思考/感触到了一些期望表达的内容,只有写下来才能让心境平复。
前几年的间隙我玩过星球、社群、直播,参与过播客,旁观过课程,这些自媒体形式我肯定不会做。
在我有限的认知里,这些事情都不性感,完全是劳动密集型的行业。我100%抗拒需要付出同等成本的事情,而且得到的收益远没有本职工作来的实在。
持续的写,站在表达自身的角度,写想写的内容,不是他人想看的内容。写我舒服的表达形式,不是可能带来更多阅读的方式。
文件上传和下载 文件下载 1.使用ResponseEntity实现下载文件的功能 需要在 webapp/static/img 下 放一张叫 1.png的图片
@RequestMapping("/testDown") public ResponseEntity<byte[]> test(HttpSession session) throws Exception { //获取ServletContext对象 ServletContext servletContext = session.getServletContext(); //获取服务器中的文件的真实路径 String realPath = servletContext.getRealPath("/static/img/1.png"); //创建输入流 InputStream is = new FileInputStream(realPath); //创建字节数组 byte[] bytes = new byte[is.available()]; //将流读取到字节数组中 is.read(bytes); //创建HttpHeaders对象 设置响应头信息 MultiValueMap<String,String> headers = new HttpHeaders(); //设置要下载方式及下载文件的名字 headers.add("content-Disposition","attachment;filename=1.png"); //设置响应状态码 HttpStatus code = HttpStatus.OK; //创建ResponseEntity对象 ResponseEntity<byte[]> entity = new ResponseEntity<>(bytes,headers,code); //关闭输入流 is.close(); return entity; } 文件上传 文件上传要求form的请求方式必须为 post,并且添加属性enctype="multipart/form-data"
springmvc中将上传的文件封装到MultipartFile对象中,通过此对象可以获取文件相关信息
南丁格尔玫瑰图(也称为极坐标条形图)可以使用R语言的ggplot2库来创建。首先,确保你已经安装了ggplot2库。如果还没有安装,可以使用以下代码来安装它:
install.packages("ggplot2") 一旦安装了ggplot2,你可以使用下面的示例代码创建南丁格尔玫瑰图:
假设有一个包含类别和频率的数据集,例如:
# 创建示例数据集 data <- data.frame( category = rep(c("A", "B", "C", "D"), each = 3), frequency = c(10, 15, 8, 12, 6, 9, 5, 14, 11, 7, 13, 9) ) 然后,使用ggplot2创建南丁格尔玫瑰图:
library(ggplot2) # 将频率转换为角度 data$angle <- 2 * pi * data$frequency / sum(data$frequency) # 创建南丁格尔玫瑰图 ggplot(data, aes(x = category, y = frequency, fill = category)) + geom_bar(stat = "identity", width = 1) + coord_polar(theta = "y") + theme_minimal() 这段代码将创建一个简单的南丁格尔玫瑰图,其中data是你的数据集,包含类别和频率列。你可以根据自己的数据调整代码以适应你的需求。
公众号关注 「奇妙的 Linux 世界」
设为「星标」,每天带你玩转 Linux !
需求场景 同一应用的不同 Pod 可能其利用率是不同的。
在对应用执行缩容操作时, 可能希望移除利用率较低的 Pod。
为了避免频繁更新 Pod,应用应该在执行缩容操作之前更新一次 controller.kubernetes.io/pod-deletion-cost 注解值 (将注解值设置为一个与其 Pod 利用率对应的值)。如果应用自身控制器缩容操作时(例如 Spark 部署的驱动 Pod),这种机制是可以起作用的。
controller.kubernetes.io/pod-deletion-cost 通过使用 controller.kubernetes.io/pod-deletion-cost 注解,用户可以对 ReplicaSet 缩容时要先删除哪些 Pod 设置偏好。
• 类别:注解
• 特性状态: Kubernetes v1.22 [beta]
• 例子:controller.kubernetes.io/pod-deletion-cost: "10"
• 用于:Pod
• 该注解用于设置 Pod 删除成本允许用户影响 ReplicaSet 缩减顺序。注解解析为 int32 类型。
此注解要设置到 Pod 上,取值范围为 [-2147483647, 2147483647]。所代表的是删除同一 ReplicaSet 中其他 Pod 相比较而言的开销。删除开销较小的 Pod 比删除开销较高的 Pod 更容易被删除。
Pod 如果未设置此注解,则隐含的设置值为 0。负值也是可接受的。如果注解值非法,API 服务器会拒绝对应的 Pod。
阻塞队列是一种特殊的队列,也遵守 "先进先出" 的原则。
阻塞队列能是一种线程安全的数据结构, 并且具有以下特性:
当队列满的时候, 继续入队列就会阻塞, 直到有其他线程从队列中取走元素;当队列空的时候, 继续出队列也会阻塞, 直到有其他线程往队列中插入元素。 JAVA标准库中已经实现了阻塞队列,我们可以直接进行使用
BlockingQueue BlockingQueue是一个接口,阻塞队列也和普通队列一样有两种实现方式:数组和链表。
注:创建阻塞队列时需要传入队列的长度参数。
BlockingQueue<String> queue = new ArrayBlockingQueue(10); 由于 BlockingQueue继承自Queue所以普通队列的接口也可以正常使用,但是没有阻塞效果。
BlockingQueue提供了两个带有阻塞效果且线程安全的方法:put()和take()。
public static void main(String[] args) throws InterruptedException { //创建一个长度为10的阻塞队列 BlockingQueue<String> queue = new ArrayBlockingQueue(10); //入队五次 queue.put("1"); queue.put("2"); queue.put("3"); queue.put("4"); queue.put("5"); //出队列六次 System.out.println(queue.take()); System.out.println(queue.take()); System.out.println(queue.take()); System.out.println(queue.take()); System.out.println(queue.take()); //由于此时队列为空,所以会出现阻塞 System.out.println(queue.take()); } 为了更好的理解阻塞队列我们可以自己设计一个简单的阻塞队列。
模拟实现 先写一个普通的循环队列
public class MyBlockingQueue { private String[] queue = new String[10]; //表示队列内元素数量 private int size; //头尾指针 private int head; private int tail; //入队列 public boolean put(String str) { if (this.
TCP的三次握手四次挥手实质就是客户端通过TCP协议与服务端进行的断开与连接
1.TCP的三次握手:
首先:
第一次握手:客户端向服务端发送SYN报文
第二次握手:服务端收到SYN数据包后向客户端发送带有ACK/SYN的数据包表示我收到了
第三次握手:客户端发送ACK报文向服务端表示我收到了 两者建立连接。
2.为什么不可以两次握手:
若只有两次握手,客户端向服务端传输发送ACK报文发生滞留,再次发送SYN报文,与服务端建立连接,滞留的SYN报文此时到达服务端,服务端会认为客户端需要两个连接,从而再次向客户端发送ACK/SYN报文,而客户端认为是一个连接,从而导致双方的状态不一致
若是三次握手,服务端发送SYN/ACK报文之后,如果收不到客户端的ACK报文确认包,则双方不会建立网络连接,从而有效的解决了网络通信问题
3.TCP 的四次挥手:
TCP通过四次挥手使客户端和服务端断开连接
第一次挥手:客户端向服务端发送TCP断开连接请求的FIN包,此时客户端进入FIN_WAIT_1状态
第二次挥手:服务端向客户端发送TCP连接请求断开的数据包,此时服务端进入CLOSE_WAIT状态
第三次挥手:服务端再次向客户端发送数据包,以此来检查TCP请求断开的数据包是否送达,若送达,则关闭两者之间的数据传输。
第四次挥手:客户端收到服务端断开TCP的数据包,会回复客户端的断开请求
Git 是一个非常强大的分布式版本控制系统,它的分支、合并和标签都非常方便,这些功能使协作开发变得简单。其中一个最常见的功能就是“Fork”,它允许开发者复制一个已有的 Git 仓库,并在复制出来的仓库上进行修改和提交。这篇文章将为你介绍 Git 的 Fork 功能,以及如何使用 Git Fork。
一、什么是 Fork 在 Git 中,Fork 是指复制一个已有的 GitHub 项目到自己的账户下,然后在自己的账户中对该项目进行操作。Fork 操作在协作开发中非常常见,它可以帮助开发者更好地参与到开源项目中来。当一个开源项目被 fork 后,其他开发者可以在自己的 fork 项目中修改代码,然后通过 Pull Request 向原项目提交代码贡献,既方便了个人的开发,也为原项目贡献了更多的代码。
Fork 操作只在远程仓库中进行,不会影响你的本地代码库。每个 fork 项目都有自己的远程仓库地址,可以在自己的 Github 仓库中找到。
二、如何进行 Fork 操作 1.打开要 Fork 的 Github 项目页面 首先,用浏览器打开要 Fork 的 Github 项目页面。在项目页面右上方,会有一个“Fork”按钮,单击它即可开始 Fork 操作。
2.选择要 Fork 的账户 在单击“Fork”按钮之后,弹出一个选择框,要求你选择要 Fork 的账户。你可以选择 Fork 到自己的仓库中,或者是 Fork 到一个组织的仓库中,具体取决于你的需求。
3.等待 Fork 完成 在选择 Fork 账户之后,Github 就会开始复制原始项目到你的 Github 仓库中。该操作可能需要几秒钟甚至几分钟才能完成。
4.访问你的 Fork 项目 当 Fork 操作完成后,你就可以在你的 Github 账户中找到你新加的 Fork 项目了。你可以点击该项目,查看它的内容,以及对它进行修改和提交。在这个过程中,所有的操作都是在你的 Fork 项目中进行的,不会影响原始项目。
以上图片来自微信朋友圈:这种天气你有什么破事打电话给我基本没用。但是如果你说“吃火锅”,那就厉害了,我们的故事就开始了。
本题要求你实现一个程序,自动检查你朋友给你发来的信息里有没有 chi1 huo3 guo1。
输入格式: 输入每行给出一句不超过 80 个字符的、以回车结尾的朋友信息,信息为非空字符串,仅包括字母、数字、空格、可见的半角标点符号。当读到某一行只有一个英文句点 . 时,输入结束,此行不算在朋友信息里。
输出格式: 首先在一行中输出朋友信息的总条数。然后对朋友的每一行信息,检查其中是否包含 chi1 huo3 guo1,并且统计这样厉害的信息有多少条。在第二行中首先输出第一次出现 chi1 huo3 guo1 的信息是第几条(从 1 开始计数),然后输出这类信息的总条数,其间以一个空格分隔。题目保证输出的所有数字不超过 100。
如果朋友从头到尾都没提 chi1 huo3 guo1 这个关键词,则在第二行输出一个表情 -_-#。
输入样例 1: Hello! are you there? wantta chi1 huo3 guo1? that's so li hai le our story begins from chi1 huo3 guo1 le . 输出样例 1: 5 3 2 输入样例 2: Hello! are you there? wantta qi huo3 guo1 chi1huo3guo1? that's so li hai le our story begins from ci1 huo4 guo2 le .
传说这是集美大学的学生对话。本题要求你做一个简单的自动问答机,对任何一个问句,只要其中包含 PTA 就回答 Yes!,其他一概回答 No.。
输入格式: 输入第一行给出一个整型范围内的正整数 N,随后 N 行,每行给出一个长度不超过 80 的字符串,为用户输入的句子,由英文字母、数字、空格和标点符号组成,以回车结束。
输出格式: 对每一行句子,如果其结尾字符为问号 ? 则判断此句中有无 PTA?如果有则在一行中输出 Yes!,否则输出 No.。如果不是问号结尾,则敷衍地回答 enen。
输入样例: 5 Hello! Do you still play WZRY? Chi Ji? you play PTA ah? how about pta site? 输出样例: enen No. No. Yes! No. #include<bits/stdc++.h> using namespace std; int main(){ int n;string s; cin>>n; getchar(); while(n--){ getline(cin,s); if(s[s.size()-1]!='?')cout<<"enen\n"; else{ if(s.find("PTA")!=-1)cout<<"Yes!\n"; else cout<<"No.\n";} } return 0; }
目录
1.原理
2.代码
2.1 key_filter.v
2.2 tb_key_filter.v
1.原理 按键分为自锁式按键和机械按键,图左边为自锁式按键
上图为RS触发器硬件消抖,当按键的个数比较多时常常使用软件消抖。硬件消抖会使用额外的器件占用电路板上的空间。
思路就是使用延时程序去掉抖动的部分,抖动就是不规则的高低电平变化。
只要在20ms之内没有抖动的产生,就可以认为按键的可用的。计数器的作用就是当检测道低电平时就开始计数,当检测到高电平时就清零。
因为50MHZ的时钟,周期为20ns,要计满20ms,20ms=20000_000ns,则计数器要计数20000_000/20=1000_000个时钟周期,所以计数器的值是从0-999_999。
出现了一个问题,若稳定的时间足够长,在稳定期间就会出现多次清零,多个最大值,多个脉冲信号,这不是我们想要的结果。为此对波形图做修改。
此时的原理就是当计数道最大值时计数器不清零,直到下一个按键输入检测到为高电平再清零。
但此时输出信号就不再是一个脉冲信号了,而是一个长长的高电平。因此再次对波形图做修改。
当计数到999_999-1时,就把输出拉高一个时钟周期,然后清零。
以上这张图的tb_cnt是为了仿真的。19-49(前抖动),149-199赋值随机数模拟抖动(后抖动),0-19,199-249赋值为高电平模仿按键未被按下,其余时间赋值为0模仿按键按下。
2.代码 2.1 key_filter.v module key_filter #( parameter CNT_MAX=20'd999_999 ) ( input wire sys_clk , input wire sys_rst_n , input wire key_in , output reg key_flag ); reg [19:0] cnt_20ms ; always @(posedge sys_clk or negedge sys_rst_n) if (sys_rst_n==1'b0) cnt_20ms<=20'd0; else if(key_in==1'b1) cnt_20ms<=20'd0; else if(cnt_20ms==CNT_MAX) cnt_20ms<=CNT_MAX; else cnt_20ms<=cnt_20ms+20'd1; always @(posedge sys_clk or negedge sys_rst_n) if (sys_rst_n==1'b0) key_flag<=1'b0; else if(cnt_20ms==CNT_MAX-20'd1) key_flag<=1'b1; else key_flag<=1'b0; endmodule 2.
创建一个标题为Hello World的窗口,窗口中间显示有Pygame的Logo的python代码
import sys import pygame def main(): pygame.init() screen = pygame.display.set_mode((800, 400)) pygame.display.set_caption("Hello World") logo = pygame.image.load("pygame.png") logo_rect = logo.get_rect() logo_rect.center = (400, 200) while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() screen.fill((255, 255, 255)) screen.blit(logo, logo_rect) pygame.display.update() if __name__ == "__main__": main() 首先,我们导入了sys和pygame这两个库。sys库用于在程序退出时使用exit()函数,而pygame库是我们使用的游戏开发库。
然后,我们定义了一个名为main()的函数作为程序的主要逻辑。在main()函数中,我们首先调用pygame.init()来初始化Pygame库的相关模块。
接下来,我们使用pygame.display.set_mode((800, 400))函数创建了一个尺寸为800×400像素的游戏窗口,并将返回的窗口对象赋值给screen变量。我们还使用pygame.display.set_caption("Hello World")设置了窗口的标题为"Hello World"。
然后,我们使用pygame.image.load("pygame.png")加载了一个名为"pygame.png"的Logo图片,并将返回的图片对象赋值给logo变量。我们使用logo.get_rect()获取了Logo图片所在的矩形区域,并将返回的矩形对象赋值给logo_rect变量。接着,我们使用logo_rect.center = (400, 200)将Logo图片所在的矩形移动到窗口的中心位置。
在进入游戏循环之前,我们使用while True创建了一个无限循环。在每次循环中,我们使用pygame.event.get()获取消息队列中的所有事件,并使用for循环对每个事件进行处理。在这里,我们判断如果事件类型是pygame.QUIT,即用户关闭了窗口,就调用pygame.quit()和sys.exit()来退出程序。
循环的其余部分用于屏幕的绘制。我们使用screen.fill((255, 255, 255))将屏幕填充为白色,然后使用screen.blit(logo, logo_rect)将Logo图片绘制在屏幕上,绘制的位置是logo_rect所定义的矩形的左上角位置。最后,我们使用pygame.display.update()函数来更新屏幕上的内容,使得所有的绘制操作都能显示在屏幕上。
通过以上代码,我们可以创建一个具有标题为"Hello World"的窗口,窗口中间显示着Pygame的Logo。循环将持续运行,直到用户关闭窗口。
第1~3行:首先引入相关的库,即sys和pygame,引入sys的目的是使用其中的exit()函数。下面分析main()函数中的代码。
第7行:该函数用来初始化Pygame中的所有相关模块,在执行其他操作前,必须调用该函数。
第9行:该函数是Pygame创建游戏窗口的核心函数,虽然其名字并不直观,但其功能确实如此。该函数创建了一个尺寸为800×400像素的游戏窗口,其参数为窗口尺寸,返回值为Surface对象,代表整个游戏窗口所在的显示区域。
🍎个人博客:个人主页
🏆个人专栏: JAVA ⛳️ 功不唐捐,玉汝于成
目录
前言 正文
分段锁的好处:
结语
我的其他博客
前言 在Java 8中,ConcurrentHashMap的实现经历了重大的改进,其中最引人注目的变化之一就是舍弃了传统的分段锁机制,转而采用了基于CAS操作的新型分段锁设计。这一变革使得ConcurrentHashMap更好地适应了高并发环境,充分发挥了现代多核处理器的性能潜力。本文将深入探讨为何在Java 8中舍弃传统分段锁,以及新设计的优势和影响。
正文 Java 8中的ConcurrentHashMap引入了新的实现方式,即采用了基于CAS (Compare and Swap) 操作的分段锁的设计,而不再使用Java 7及之前版本中的传统分段锁。
Java 8 ConcurrentHashMap的设计采用了一种更加细粒度的锁机制,即将整个Map分为多个段(segment),每个段维护一部分键值对。相比于整个Map使用一个大锁的传统方式,这种分段锁的设计可以降低锁的粒度,提高并发性能。
分段锁的好处: 细粒度的锁: 每个段都有自己的锁,这样在多线程环境中只有在需要同步的地方才会进行锁的竞争,降低了锁的争用情况。
提高并发性能: 因为只有在操作同一个段的时候才会出现锁竞争,所以各个段之间的操作可以并行执行,提高了并发性能。
减小锁的持有时间: 操作只需要对影响的段进行加锁,而不是整个Map,减小了锁的持有时间,提高了并发度。
减小了死锁的可能性: 锁的范围缩小到了每个段,降低了死锁的可能性。
总体来说,Java 8中的ConcurrentHashMap采用分段锁的设计是为了更好地支持高并发的场景,提高了程序的性能和并发度。这种设计的优势在于能够在保证线程安全的同时,最大程度地减小锁的争用,提高并发性能。
结语 通过舍弃传统的分段锁,Java 8中的ConcurrentHashMap迈出了更为灵活和高效的一步。新的基于CAS的分段锁设计在提高并发性能、降低锁争用、减小锁持有时间等方面都取得了显著的成果。这个设计决策使得ConcurrentHashMap成为高并发场景中首选的数据结构之一,为开发人员提供了更好的工具,以便更好地处理多线程环境下的数据访问和修改。通过本文的了解,读者可以更深入地理解Java 8中ConcurrentHashMap的内部实现和其在多线程应用中的性能优势。
我的其他博客 【软件工程】走进敏捷开发:灵活、协作、迭代的软件工艺之旅-CSDN博客
【软件工程】融通未来的工艺:深度解析统一过程在软件开发中的角色-CSDN博客
【软件工程】走进瀑布模型:传统软件开发的经典之路-CSDN博客
【软件工程】走近演化过程模型:软件开发的不断进化之路-CSDN博客
【软件工程】漫谈增量过程模型:软件开发的逐步之道-CSDN博客
【Spring】理解IoC与AOP:构建灵活而模块化的软件架构-CSDN博客
【MySQL】数据库并发控制:悲观锁与乐观锁的深入解析-CSDN博客
【MySQL】数据库规范化的三大法则 — 一探范式设计原则-CSDN博客
【MySQL】数据库中为什么使用B+树不用B树-CSDN博客
【MySQL】SQL优化-CSDN博客
【MySQL】脏读、不可重复读、幻读介绍及代码解释-CSDN博客
【MySQL】多表连接查询-CSDN博客
【MySQL】数据库索引(简单明了)-CSDN博客
【Web开发】深度剖析RBAC:概念、实现方法、优势及在Web应用中的应用-CSDN博客
【Mybatis】深入学习MyBatis:高级特性与Spring整合-CSDN博客
【Mybatis】深入学习MyBatis:CRUD操作与动态SQL实战指南-CSDN博客
【MySQL】数据库索引(简单明了)-CSDN博客
🍎个人博客:个人主页
🏆个人专栏: JAVA ⛳️ 功不唐捐,玉汝于成
目录
前言 正文
示例:
不可修改的List:
不可修改的Set:
不可修改的Map:
结语
我的其他博客
前言 在软件开发中,数据的管理和处理是至关重要的一环。在某些情况下,我们希望确保某个集合的内容在一定时间内不被修改,以保持数据的一致性和稳定性。Java提供了一种简单而有效的方法,即使用Collections.unmodifiableXXX方法,来创建不可修改的集合视图。通过这种方式,我们可以在代码中明确表达对于数据不可变性的要求,从而更好地设计和维护程序。
正文 在Java中,可以使用Collections.unmodifiableXXX方法来确保一个集合不能被修改,其中XXX可以是List、Set或Map等。这些方法返回一个不可修改的视图,任何试图修改这个视图的操作都会抛出UnsupportedOperationException异常。
示例: 不可修改的List: List<String> originalList = new ArrayList<>(); originalList.add("Item 1"); originalList.add("Item 2"); List<String> unmodifiableList = Collections.unmodifiableList(originalList); // 尝试修改将抛出 UnsupportedOperationException 异常 unmodifiableList.add("Item 3"); 不可修改的Set: Set<Integer> originalSet = new HashSet<>(); originalSet.add(1); originalSet.add(2); Set<Integer> unmodifiableSet = Collections.unmodifiableSet(originalSet); // 尝试修改将抛出 UnsupportedOperationException 异常 unmodifiableSet.add(3); 不可修改的Map: Map<String, Integer> originalMap = new HashMap<>(); originalMap.put("Key 1", 1); originalMap.put("Key 2", 2); Map<String, Integer> unmodifiableMap = Collections.
前言 由于3D相机采集到的数据通常通过Tiff格式的深度图进行显示或者保存。
深度图与模型的互转可以访问另一篇博客:https://blog.csdn.net/m0_51559565/article/details/135362674
关于3D相机的数据采集,可以访问我们另一篇关于LMI3D相机SDK的二次开发:
https://blog.csdn.net/m0_51559565/article/details/134404394
一:处理流程 常见的3D数据通常以Z轴作为灰度值的深度图的形式出现。所以我们可以根据2D图的特性,对2D图先进行灰度二值化筛选,图像增强,滤波等方式提取特征点。转换为3D模型后可以通过对点云的欧式距离进行点云集的拆分。
二:灰度筛选与滤波 *读取图像 read_image (Image, 'E:/UpperComputer/3D检测/点云筛选和滤波/XYZ彩色融合图.tiff') *拆分3通道,对Z通道进行单独处理 decompose3 (Image, x, y, z) *通过选取灰度值,直接找到所需的区域 threshold (z, Regions, 114.83, 145.83) *将区域进行裁剪 reduce_domain (z, Regions, ImageReduced) crop_domain (ImageReduced, ImagePart) *通过ROI的形式剔除边缘不适合的点云 gen_rectangle1 (ROI_0, 145.41, 81.8859, 509.72, 397.831) reduce_domain (ImagePart, ROI_0, ImageReduced1) crop_domain (ImageReduced1, ImagePart1) *滤波。可以去除由于相机过曝造成的点云 *mean_image (ImagePart1, ImageMean, 9, 9) *median_image (ImagePart1, ImageMedian, 'circle', 1, 'mirrored') gauss_filter (ImagePart1, ImageGauss, 5) 原始图像
灰度二值化处理,与ROI拆分。在实际处理中,为了可以快速的完成对特征区域的匹配,通过会直接通过ROI的形式,当然不局限于还有,例如模板匹配,圆形测量等常用的2D图像提取方法。
三:点云筛选 在进行完预处理后,通常点云的去噪效果非常好,或者几何完成的情况。但是对于部分特殊情况。例如,由于相机过曝或者强反光的金属表面造成的点云波动,通常这类型的波动情况往往点云数少,高度差距小,所以比较难发现。
通常可以直接使用点云欧式距离。例如下面,对点云欧式距离大于5的点云进行区分(点云间的距离等于5个点的距离)。然后根据我们需要的点云数进行筛选即可
connection_object_model_3d (ObjectModel3D, 'distance_3d', 5, ObjectModel3DConnected) select_object_model_3d (ObjectModel3DConnected, 'num_points', 'and', 100, 1000000000, ObjectModel3DSelected) 结尾 通常情况下说,灰度二值化将要测量的平面选取出来,然后进行均值滤波,让平面变得光滑,去除噪点,在通过选取ROI去除边缘点云采样不理想的区域。基本可以完成对点云的预处理了。最后根据点云间的距离,还可以进一步的去除噪点。到最后基本就可以完成对点云的处理,方式适用于大部分3D检测和缺陷检测的项目。但是对倾斜面无需抓取项目仍有待考究
常见算法的时间复杂度 规定n是数组的长度/树或图的节点数
二分查找:O(logn)
双指针/滑动窗口:O(n)
DFS/BFS:O(n)
构建前缀和:O(n)
查找前缀和:O(1)
一维动态规划:O(n)
二维动态规划:O(n^2)
回溯:O(2^n)/O(n!)
下面重点来辣
数据范围反推时间复杂度 数据范围:n~100 O(n!)/O(2^n)的时间复杂度
应该考虑回溯或任何蛮力式的递归算法
如:全排列、组合、N皇后
数据范围:n~1,000 O(n^2)的时间复杂度
通常涉及双重循环,内层循环可能涉及双指针、dp等等
如:三数之和、最接近的三数之和
数据范围:n~100,000 O(logn)/O(n)/O(nlogn)的时间复杂度
双重循环无法通过,但可以接受直接遍历,很多贪心/双指针的问题
如:两数之和、盛最多水的容器、救生艇
数据范围:n~1,000,000 O(1)/O(logn)的时间复杂度
涉及二分查找或数学解法
如:数字1的个数、猜数字大小
程序运行时间和什么有关 数据量大小
算法的好坏
ChatGPT4.0国内站点:海鲸AI
在CSS中,你可以通过设置一个元素的边框来制作三角形。这是一个常用的技巧,它涉及将一个元素的宽度和高度设置为0,然后只为边框的某些部分设置颜色,其他部分设置为透明。以下是一个简单的例子,展示了如何创建一个向上指的三角形:
.triangle-up { width: 0; height: 0; border-left: 50px solid transparent; border-right: 50px solid transparent; border-bottom: 100px solid black; /* 这是三角形的颜色 */ } <div class="triangle-up"></div> 在这个例子中,.triangle-up 类被添加到一个 div 元素上。这个 div 的左右边框被设置为透明,底边框被设置为黑色。结果就是一个向上指的三角形。
如果你想创建一个指向不同方向的三角形,你可以调整边框的设置。例如:
向下指的三角形:设置上边框的颜色,左右边框透明,底边框宽度为0。向左指的三角形:设置右边框的颜色,上下边框透明,左边框宽度为0。向右指的三角形:设置左边框的颜色,上下边框透明,右边框宽度为0。 记得,你可以随意调整边框的宽度来改变三角形的大小。
第1章:引言 大家好,我是小黑,咱们今天来聊聊Java线程池,如果没有线程池,每个线程都需要手动创建和销毁线程,那将是多么低效和耗资源啊!
线程池的核心作用就是复用已创建的线程,减少系统开销,提高响应速度。咱们在开发高并发应用时,经常会遇到需要同时执行多个任务的场景,这时候线程池就闪亮登场了。它能够合理分配每个任务到线程,实现资源的最优使用。
但别小看了这个线程池,用得不好可是会出大问题的。比如,线程池大小配置不当,可能会导致系统崩溃,或者效率低下。所以,小黑今天就带大家深入浅出地探索Java线程池的奥秘,一起学习如何调优和监控它。
第2章:Java线程池概述 讲到线程池,咱们得先了解下Java里面线程池的基本构成。Java中的线程池主要依靠java.util.concurrent包里的ThreadPoolExecutor类来实现。它是一个强大的工具,可以帮助咱们有效地管理线程资源。
线程池的工作原理大概是这样的:有一个线程池管理器(ThreadPoolExecutor),负责创建和管理线程池;还有一个工作队列,用来存放待处理的任务;还有若干个工作线程,执行这些任务。
咱们先来看一段基础的线程池创建代码,小黑会一步一步解释:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPoolDemo { public static void main(String[] args) { // 创建一个固定大小的线程池 ExecutorService threadPool = Executors.newFixedThreadPool(5); for (int i = 1; i <= 10; i++) { final int taskId = i; threadPool.execute(() -> { System.out.println("执行任务:" + taskId + ",线程名:" + Thread.currentThread().getName()); }); } threadPool.shutdown(); // 关闭线程池 } } 这段代码创建了一个固定大小为5的线程池。Executors.newFixedThreadPool(5)这一行代码就完成了这个魔法。然后,咱们通过一个循环创建了10个任务,通过threadPool.execute()方法提交到线程池中执行。每个任务只是简单地打印出它的任务ID和执行它的线程名。
注意到了吗?这里咱们使用了shutdown()方法来关闭线程池。这是因为线程池用完之后,如果不关闭,那么它里面的线程会一直处于等待状态,这样会导致资源浪费。
第3章:线程池的核心参数解析 1. ThreadPoolExecutor的关键参数 当咱们创建一个线程池的时候,通常会遇到几个关键的参数,它们决定了线程池的行为和性能:
corePoolSize(核心线程数): 这个参数表示线程池中常驻的线程数量。即使线程空闲,线程池也不会释放这些线程。maximumPoolSize(最大线程数): 线程池能容纳的最大线程数。当工作队列满了之后,线程池会创建新线程,直到达到这个上限。keepAliveTime(线程保持活动时间): 当线程数超过核心线程数时,这是超出部分线程在空闲时的存活时间。unit(时间单位): keepAliveTime的时间单位。workQueue(工作队列): 存放待处理任务的队列。它通常是一个BlockingQueue的实现类。threadFactory(线程工厂): 用于创建新线程的工厂。handler(拒绝策略): 当线程池和工作队列都满了,如何处理新提交的任务。 2.
文章目录 1、字体大小设置2、行号显示3、快速跳转到某一行4、在所有文件中的搜索某一函数使用情况5、换行自动对齐6、取消程序名后的文件路径显示 1、字体大小设置 【Options】->【Preferences】->【Typing】->【Per File Type】->【Screen Font】
2、行号显示 【View】->【Line Numbers】
3、快速跳转到某一行 Ctrl+G
4、在所有文件中的搜索某一函数使用情况 Ctrl+/
5、换行自动对齐 】Options】->】File type Options】,选择】Auto Indent…】弹出对话框,将】Smart Indent Options】下的两个复选框的√去掉即可
6、取消程序名后的文件路径显示 点击文件名->Windows Tab Options,进去取消勾选即可
文章目录 Join查询原理Nested-Loop JoinINNER JOIN、LEFT JOIN、RIGHT JOIN的区别INNER JOIN操作LEFT JOIN操作RIGHT JOIN操作总结 参考 Join查询原理 查询原理:MySQL内部采用了一种叫做 Nested Loop Join(嵌套循环连接) 的算法。Nested Loop Join 实际上就是通过 驱动表的结果集 作为循环基础数据,然后一条一条的通过 该结果集 中的数据作为过滤条件到下一个表中查询数据,然后合并结果。如果还有第三个参与 Join,则再通过前两个表的 Join 结果集作为循环基础数据,再一次通过循环查询条件到第三个表中查询数据,如此往复,基本上MySQL采用的是最容易理解的算法来实现join。所以驱动表的选择非常重要,驱动表的数据小可以显著降低扫描的行数。
一般情况下参与联合查询的两张表都会一大一小,如果是join,在没有其他过滤条件的情况下MySQL会自动选择小表作为驱动表。简单来说,驱动表就是主表,left join中的左表就是驱动表,right join中的右表是驱动表。
Nested-Loop Join 在Mysql中,使用Nested-Loop Join的算法思想去优化join,Nested-Loop Join翻译成中文则是“嵌套循环连接”。
mysql只支持一种join算法:Nested-Loop Join(嵌套循环连接),但Nested-Loop Join有三种变种:
Simple Nested-Loop Join:SNLJ,简单嵌套循环连接Index Nested-Loop Join:INLJ,索引嵌套循环连接Block Nested-Loop Join:BNLJ,缓存块嵌套循环连接
在选择Join算法时,会有优先级,理论上会优先判断能否使用INLJ、BNLJ:Index Nested-LoopJoin > Block Nested-Loop Join > Simple Nested-Loop Join INNER JOIN、LEFT JOIN、RIGHT JOIN的区别 接下来通过例子帮助理解他们之间的区别
首先,我们创建示例数据库和表。同时也要明确一个概念:A INNER/LEFT/RIGHT JOIN B操作中,A表被称为左表,B表被称为右表。
创建示例数据库school,在数据库school下创建两张示例表:student、punishment。
创建学生基本信息表student,如下:
DROP TABLE IF EXISTS `punishment`; CREATE TABLE `punishment` ( `student_id` char(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, `punishment` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, PRIMARY KEY (`student_id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '学生违纪处罚记录表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of punishment -- ---------------------------- INSERT INTO `punishment` VALUES ('201400002', '张三', '大过'); INSERT INTO `punishment` VALUES ('201400006', '杨智', '留校察看'); INSERT INTO `punishment` VALUES ('201400009', '陈子丹', '小过'); 创建学生违纪处罚记录表punishment,如下:
场景 之前我们通过k近邻算法和决策树做出了 分类,这是分类器会给出一个艰难的预测的最优的结果,我们可以根据这个结果做出决策,但是这个结果如果是错误的,就芭比扣了。我现在想要分类器不仅仅给我一个最优结果,我还想分类器给我一个这个结果对应的概率。这时候我们可以采用贝叶斯决策理论。
贝叶斯决策理论 百度对其的描述是: 贝叶斯决策理论,是主观贝叶斯派归纳理论的重要组成部分。 贝叶斯决策就是在不完全情报下,对部分未知的状态用主观概率估计,然后用贝叶斯公式对发生概率进行修正,最后再利用期望值和修正概率做出最优决策。 我听不懂,不妨以一个高数题入局。当我还是个大学生的时候,觉得高数没什么用,现在觉得自己当时太年轻了。
废话就不说了,我们做一个高数题:
人的性别由一对性染色体决定:男为XY,女为XX,每个人从父母处各得到一个性染色体,色盲基因由X染色体携带,且若男性的X染色体有此基因则男性患色盲,女性则要两个X染色体均有此基因才患色盲,而两个X是否有色盲基因是独立的。设色盲基因出现概率为0.08。又设男女婴出生比为110:100。问一新生儿有色盲的概率是多少? 这是一个高数的典型题目,其实不难,我们只要知道,男孩如果出现色盲基因必须是色盲,概率是百分比,女生是色盲的概率是 色盲基因 ** 2。那么结果是
# 定义已知概率 p_colorblind_gene = 0.08 # 色盲基因出现的概率 ratio_male = 110 # 男性新生儿比例 ratio_female = 100 # 女性新生儿比例 total_newborns = ratio_male + ratio_female # 总新生儿数 # 计算男性和女性新生儿患色盲的概率 p_colorblind_male = p_colorblind_gene p_colorblind_female = p_colorblind_gene**2 # 计算男性和女性的比例 p_male = ratio_male / total_newborns p_female = ratio_female / total_newborns # 使用全概率公式计算新生儿患色盲的总概率 p_colorblind_total = (p_colorblind_male * p_male) + (p_colorblind_female * p_female) print(p_colorblind_total) 答案是约等于 0.
JVM 基础 - Java 类加载机制 类的生命周期类的加载: 查找并加载类的二进制数据连接验证: 确保被加载的类的正确性准备: 为类的静态变量分配内存,并将其初始化为默认值解析: 把类中的符号引用转换为直接引用 初始化使用卸载 类加载器, JVM类加载机制类加载器的层次寻找类加载器类的加载 JVM类加载机制自定义类加载器 类的生命周期 其中类加载的过程包括了加载、验证、准备、解析、初始化五个阶段。在这五个阶段中,加载、验证、准备和初始化这四个阶段发生的顺序是确定的,而解析阶段则不一定,它在某些情况下可以在初始化阶段之后开始,这是为了支持Java语言的运行时绑定(也成为动态绑定或晚期绑定)。另外注意这里的几个阶段是按顺序开始,而不是按顺序进行或完成,因为这些阶段通常都是互相交叉地混合进行的,通常在一个阶段执行的过程中调用或激活另一个阶段。
类的加载: 查找并加载类的二进制数据 加载时类加载过程的第一个阶段,在加载阶段,虚拟机需要完成以下三件事情:
通过一个类的全限定名来获取其定义的二进制字节流。将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。在Java堆中生成一个代表这个类的java.lang.Class对象,作为对方法区中这些数据的访问入口。 相对于类加载的其他阶段而言,加载阶段(准确地说,是加载阶段获取类的二进制字节流的动作)是可控性最强的阶段,因为开发人员既可以使用系统提供的类加载器来完成加载,也可以自定义自己的类加载器来完成加载。
加载阶段完成后,虚拟机外部的 二进制字节流就按照虚拟机所需的格式存储在方法区之中,而且在Java堆中也创建一个java.lang.Class类的对象,这样便可以通过该对象访问方法区中的这些数据。
类加载器并不需要等到某个类被“首次主动使用”时再加载它,JVM规范允许类加载器在预料某个类将要被使用时就预先加载它,如果在预先加载的过程中遇到了.class文件缺失或存在错误,类加载器必须在程序首次主动使用该类时才报告错误(LinkageError错误)如果这个类一直没有被程序主动使用,那么类加载器就不会报告错误。
加载.class文件的方式
从本地系统中直接加载通过网络下载.class文件从zip,jar等归档文件中加载.class文件从专有数据库中提取.class文件将Java源文件动态编译为.class文件 连接 验证: 确保被加载的类的正确性 验证是连接阶段的第一步,这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。验证阶段大致会完成4个阶段的检验动作:
文件格式验证: 验证字节流是否符合Class文件格式的规范;例如: 是否以0xCAFEBABE开头、主次版本号是否在当前虚拟机的处理范围之内、常量池中的常量是否有不被支持的类型。元数据验证: 对字节码描述的信息进行语义分析(注意: 对比javac编译阶段的语义分析),以保证其描述的信息符合Java语言规范的要求;例如: 这个类是否有父类,除了java.lang.Object之外。字节码验证: 通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。符号引用验证: 确保解析动作能正确执行。 验证阶段是非常重要的,但不是必须的,它对程序运行期没有影响,如果所引用的类经过反复验证,那么可以考虑采用-Xverifynone参数来关闭大部分的类验证措施,以缩短虚拟机类加载的时间。
准备: 为类的静态变量分配内存,并将其初始化为默认值 准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些内存都将在方法区中分配。对于该阶段有以下几点需要注意:
这时候进行内存分配的仅包括类变量(static),而不包括实例变量,实例变量会在对象实例化时随着对象一块分配在Java堆中。这里所设置的初始值通常情况下是数据类型默认的零值(如0、0L、null、false等),而不是被在Java代码中被显式地赋予的值。
假设一个类变量的定义为: public static int value = 3; 那么变量value
在准备阶段过后的初始值为0,而不是3,因为这时候尚未开始执行任何Java方法,而把value赋值为3的put static指令是在程序编译后,存放于类构造器<clinit>()方法之中的,所以把value赋值为3的动作将在初始化阶段才会执行。 这里还需要注意如下几点
对基本数据类型来说,对于类变量(static)和全局变量,如果不显式地对其赋值而直接使用,则系统会为其赋予默认的零值,而对于局部变量来说,在使用前必须显式地为其赋值,否则编译时不通过。对于同时被static和final修饰的常量,必须在声明的时候就为其显式地赋值,否则编译时不通过;而只被final修饰的常量则既可以在声明时显式地为其赋值,也可以在类初始化时显式地为其赋值,总之,在使用前必须为其显式地赋值,系统不会为其赋予默认零值。对于引用数据类型reference来说,如数组引用、对象引用等,如果没有对其进行显式地赋值而直接使用,系统都会为其赋予默认的零值,即null。如果在数组初始化时没有对数组中的各元素赋值,那么其中的元素将根据对应的数据类型而被赋予默认的零值。如果类字段的字段属性表中存在ConstantValue属性,即同时被final和static修饰,那么在准备阶段变量value就会被初始化为ConstValue属性所指定的值。假设上面的类变量value被定义为: public static final int value = 3; 编译时Javac将会为value生成ConstantValue属性,在准备阶段虚拟机就会根据ConstantValue的设置将value赋值为3。我们可以理解为static final常量在编译期就将其结果放入了调用它的类的常量池中 解析: 把类中的符号引用转换为直接引用 解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程,解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符7类符号引用进行。符号引用就是一组符号来描述目标,可以是任何字面量。
直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。
初始化 初始化,为类的静态变量赋予正确的初始值,JVM负责对类进行初始化,主要对类变量进行初始化。在Java中对类变量进行初始值设定有两种方式:
前言 今天,我们来用Python画房子。
一、第一种 第一种比较简单。
代码:
import turtle as t import time def go(x, y): t.penup() t.goto(x, y) t.pendown() def rangle(h,w): t.left(180) t.forward(h) t.right(90) t.forward(w) t.left(-90) t.forward(h) def leftf(a,l): t.left(a) t.forward(l) def rightr(a,l): t.right(a) t.forward(l) def square(w,h): t.forward(h) t.right(90) t.forward(w) t.right(90) t.forward(h) t.right(90) t.forward(w) t.pencolor("#2F4F4F") t.hideturtle() t.speed(100) t.bgcolor("#48D1CC") t.penup() t.goto(-600,-250) t.pendown() t.forward(950) t.goto(-400,-250) t.fillcolor("#B0E0E6") t.begin_fill() t.left(90) t.forward(15) t.right(90) t.forward(225) t.left(-90) t.forward(15) # 门子 rangle(22,150) rangle(15,225) # 柱子 go(-385,-235) rangle(15,23) go(-383,-220) rangle(100,18) go(-385,-120) t.
C语言可变参数详细介绍 C语言是一种强大而灵活的编程语言,支持可变参数函数的特性。可变参数函数允许我们在调用时传递不定数量的参数,这在某些情况下非常有用。本博客将详细介绍C语言中可变参数的概念、使用方法和一些实例。
可变参数的概念 可变参数是指函数的参数数量在调用时可以变化的特性。在C语言中,我们使用<stdarg.h>头文件中的宏和函数来处理可变参数。
va_list、va_start和va_end va_list是一个用于存储可变参数信息的类型,而va_start和va_end则用于在函数中初始化和结束可变参数的处理。
#include <stdarg.h> void example_function(int fixed_arg, ...) { va_list args; va_start(args, fixed_arg); // Access variable arguments using va_arg va_end(args); } va_arg va_arg宏用于访问可变参数列表中的每个参数。它需要两个参数,第一个是va_list,第二个是参数的类型。
int sum(int num, ...) { va_list args; va_start(args, num); int total = num; int next_arg; while ((next_arg = va_arg(args, int)) != 0) { total += next_arg; } va_end(args); return total; } 在上述例子中,我们通过一个特殊的值(这里是0)来标识可变参数的结束。
使用可变参数的实例 让我们通过一个例子来说明如何使用可变参数计算平均值:
#include <stdio.h> #include <stdarg.h> double average(int num, ...) { va_list args; va_start(args, num); double total = num; int count = 1; int next_arg; while ((next_arg = va_arg(args, int)) !
安装步骤 安装 Docker 和 Docker Compose:首先,确保您的 Linux 系统已安装 Docker 和 Docker Compose。如果未安装,您可以通过官方 Docker 文档找到安装指南。
创建 docker-compose.yml 文件:接下来,创建一个 docker-compose.yml 文件以定义 RabbitMQ 服务。这个文件告诉 Docker 如何部署 RabbitMQ 容器。
配置 RabbitMQ 服务:在 docker-compose.yml 文件中,您将指定 RabbitMQ 映像、端口、环境变量等配置。
以下是一个基本的 docker-compose.yml 文件示例,用于部署 RabbitMQ:
version: '3' services: rabbitmq: image: "rabbitmq:3-management" ports: - "5672:5672" # AMQP 协议端口 - "15672:15672" # 管理界面端口 environment: RABBITMQ_DEFAULT_USER: "user" RABBITMQ_DEFAULT_PASS: "password" volumes: - "rabbitmq_data:/var/lib/rabbitmq" volumes: rabbitmq_data: 这个配置创建了一个带有管理界面的 RabbitMQ 服务,端口 5672 用于 AMQP 协议,端口 15672 用于管理界面。它还设置了默认用户名和密码,并创建了一个持久卷来存储 RabbitMQ 数据。
枚举 一、C++枚举基础
在C++中,枚举(Enumeration)是一种用户定义的数据类型,它包含一组整数值,每个值都与一个标识符关联。通过使用枚举,我们可以使代码更加清晰易懂,避免使用魔术数字或字符串。
下面是一个简单的C++枚举示例:
enum Color {RED, GREEN, BLUE}; 在这个例子中,我们定义了一个名为Color的枚举类型,它有三个可能的值:RED、GREEN和BLUE。默认情况下,枚举值从0开始,递增1。
二、指定枚举值
除了默认的整数值,我们还可以在定义枚举时为其指定具体的值。这可以通过在枚举常量后面添加赋值运算符来实现。例如:
enum Color {RED=3, GREEN=7, BLUE=12}; 在这个例子中,我们为RED指定了值3,为GREEN指定了值7,为BLUE指定了值12。这些具体的值可以使代码更具可读性,并且有助于我们按照自己的需求进行赋值。
三、使用枚举
使用枚举的方法非常简单。以下是一个完整的示例,展示了如何声明和使用枚举:
#include <iostream> using namespace std; enum Color {RED=3, GREEN=7, BLUE=12}; int main() { Color c = GREEN; // 声明并初始化一个Color枚举变量 cout << "Color: " << c << endl; // 输出 "Color: 7" return 0; } 在这个例子中,我们声明了一个名为c的Color枚举变量,并将其初始化为GREEN。然后,我们将该变量的值打印到控制台。由于我们在定义枚举时为GREEN指定了值7,因此输出结果为"Color: 7"。
四、枚举的运算与比较
除了基本的赋值和打印操作,我们还可以对枚举进行一些运算和比较操作。例如:
加法:将一个整数值加到一个枚举值上。例如,Color::RED + 2的结果是Color::GREEN。需要注意的是,这里的加法实际上是模运算(取余数),因为枚举值的范围是有限的。减法:从一个枚举值中减去一个整数值。例如,Color::GREEN - 1的结果是Color::RED。同样地,这里的减法也是模运算。比较:可以比较两个枚举值是否相等或不相等。例如,Color::RED == Color::GREEN的结果是false。需要注意的是,这里比较的是枚举常量对应的整数值。 五、枚举的高级用法
除了基本的赋值和比较操作,我们还可以利用枚举进行更高级的编程。例如:
位运算:我们可以使用位运算来操作枚举值。例如,通过按位或运算可以将多个标志组合在一起: enum Flags {FLAG_A = 1, FLAG_B = 2, FLAG_C = 4}; Flags f = FLAG_A | FLAG_C; // f 的值为5(二进制: 101) 枚举类:我们可以使用类来封装枚举类型,以提供更严格的访问控制和额外的功能。例如: class Color { public: enum Type {RED, GREEN, BLUE}; static const char* ToString(Type t); // 将枚举值转换为字符串的静态方法 }; const char* Color::ToString(Color::Type t) { switch (t) { case RED: return "
移除两个双向链表中的重复元素,每个链表中的元素不重复,请给出算法。
ans: 该问题比单向链表要更加复杂一些,必须考虑并更新前向节点的指向情况,具体编码中存在一些难度,加上链表调试相对不容易,因此难度系数略高。
主要思路为:
为每个链表添加哨兵节点,哨兵节点方便操作,因为头节点可能为重复元素访问链表A的首元素,和链表B的元素依次做对比 当对比相等时, 移除B的当前元素,更新B的指向移除A的当前元素,更新A的指向break B 当对比不相等时, 链表B指针依次后移,直到为空 当链表B的指针指向为空时,更新链表A的指针指向,继续对比,直到链表A为空打印出链表元素,因为是双向链表,必须两个方向打印,方能确保正确。代码如下,main中运行testList即可 typedef struct Node { //双链节点 定义 int data; struct Node *prev, *next; } DList; void PrintList(DList *head) { // 打印链表, DList *cur = head; while(cur != NULL) { // 正向打印 printf("%d ", cur->data); cur = cur->next; if(cur) { printf(" -> "); } } printf(" || "); cur = head; while(cur->next != NULL) { // 寻找尾巴节点 cur = cur->next; } while(cur !
😁 作者简介:一名大四的学生,致力学习前端开发技术
⭐️个人主页:夜宵饽饽的主页
❔ 系列专栏:NodeJs
👐学习格言:成功不是终点,失败也并非末日,最重要的是继续前进的勇气
🔥前言:
本文是关于Node命令中的npm link命令的详细使用,还有脚手架的背后原理,如果我们需要开发命令行工具或者脚手架时,npm link的使用是必不可少的一环,有关环境变量部分大家一定要好好理解,希望可以帮助到大家,欢迎大家的补充和纠正
文章目录 Node命令1.CLI全局命令1.1 环境变量1.2 npm安装全局指令流程3.package.json里的bin字段 2.npm link2.1作为npm包被其他包引用在开发调试的包中执行npm link在项目中执行npm link 2.2 作为命令行工具需要直接在终端调用 最后 Node命令 1.CLI全局命令 当我们安装一个npm包之后,我们可以再电脑的任意终端使用这个npm包提供的指令,例如:当我们安装了nest npm install -g @nestjs/cli ,我们就可以在任意地方使用nest这个指令,例如:
nest new my-nest-project ,就会帮我们创建一个名字叫 my-nest-project的nest项目,这是怎么做到的呢?
1.1 环境变量 我们做格知识准备,先了解一下什么是环境变量。
环境变量就是Window一个命令执行路径:
echo %PATH% C:\Program Files\Java\jdk1.8.0_261\bin;C:\Program Files\Git\bin;C:\Windows\System32;... 上面打印出来的就是环境变量,其中有我们熟悉的java文件执行,Git指令等,当我们在终端执行某一个指令时,其会在这些路径下面寻找是否有对应的可执行文件。有就会执行,没有就报错(错误信息:不是内部或外部命令,也不是可运行的程序或批处理文件)
1.2 npm安装全局指令流程 我们在执行npm install -g @nestjs/cli之后,就可以启动nest全局命令,这是因为在环境变量的路径下创建创建了一个nest文件
//可以使用下面这个命令查询Node全局安装指令的位置。 //注意输出的位置,这个位置很重要,下文会经常用到 npm bin -g // C:\Users\AppData\Roaming\npm 在这个输出的路劲下,可以看到nest文件
这个文件会中有指向具体执行的npm包的位置:/node_modules/@nestjs/cli/bin/nest.js
所以总的执行流程可以感觉到:
输入一个nest指令 -> 在环境变量中寻找 ->找到nest可执行文件 ->执行/node_modules/@nestjs/cli/bin/nest.js 文件
3.package.json里的bin字段 我们来看nestjs包中的package.json,可以发现一个重点:
我们可以注意到与上面指令真正执行的文件是一致的,所以最终执行的是bin/nest.js
李沐(沐神)、朱毅讲得真的好,干货蛮多,值得认真读很多遍,甚至可以当成多模态大模型基础课程学习。
论文原文: An image is worth 16x16 words: transformers for image recognition at scale。
ViT取代了CNN,打通了CV和NLP之间的鸿沟,而且挖了一个更大的多模态的坑。ViT未来有可能真就是一个简洁、高效、通用的视觉骨干网络,而且可以完全不用任何标注信息。当拥有足够多的数据进行预训练的时候,ViT的表现就会超过CNN,突破transformer缺少归纳偏置的限制,可以在下游任务中获得较好的迁移效果。
如果说过去一年中在计算机视觉领域哪个工作的影响力最大,那应该非vision transformer莫属了,因为他挑战了自从2012年Alex提出以来,CNN卷积神经网络在计算机视觉领域里绝对统治的地位。它的结论就是说,如果在足够多的数据上去做预训练,那我们也可以不需要卷积神经网络,直接用一个从自然预言处理那边搬过来的标准的transformer也能把视觉问题解决的很好。而且,vision transformer不光是在视觉领域挖了一个大坑,因为它打破了CV、NLP在模型上的这个壁垒,所以在多模态领域也挖了一个大坑。于是,在短短的一年之内,各种基于vision transformer的工作层出不穷,公众的论文应该已经有上百篇了,有把它扩展到别的任务的,有对模型本身进行改进的,有对它进行分析的。还有对目标函数或者训练方式进行改进的,基本上是可以说开启了CV的一个新时代。那vision transformer到底效果有多好?我们可以先来看一下Paper with code这个网站,这个网站就是说如果你想知道现在某个领域或者某个数据集表现最好的那些方法有哪些,你就可以来查一下。
https://paperswithcode.com/sota
我们先来看图像分类在ImageNet这个数据集上。排名靠前的全都是基于vision transformer的。那如果我们换到目标检测这个任务,在COCO这个数据集上,可以看到排名前几的都是基于Swin transformer。Swin transformer是ICCV 21最佳论文,你可以把它想象成是一个多尺度的ViT。当然还有很多领域,语义分割、实例分割、视频医疗、遥感等,基本上可以说ViT把整个视觉领域里所有的任务都刷了个遍,但我们今天要读ViT这篇论文,也不光是因为它效果这么炸裂。还是因为它有很多跟CNN很不一样的特性。
咱们来看有篇题目叫做Intriguing Properties of vision transformers的论文,看看它的图一。
图一说了在卷积神经网络CNN上工作的不太好,但是用vision transformer都能处理很好的例子。
比如说第一个就是遮挡,那在这么严重的遮挡情况下,不光是卷积神经网络,其实就是人也很难看得出其中有一只鸟。第二个例子,就是数据分布上有所偏移,在这里就是对图片做了一次纹理去除的操作,所以说导致图片看起来非常魔幻,我也很难看出来其中到底是什么物体。第三个,就是说在鸟头的位置加了一个对抗性的patch。第四个,就是说把图片打散了以后做排列组合,卷积神经网络也是很难去判断这到底是一个什么物体的。
所有这些例子,vision transformer都能处理的很好,所以说鉴于ViT的效果这么好,而且它有这么多有趣的特性,跟卷积神经网络如此不一样,那所以我们今天就来精读一下这篇论文。我们先来看一下题目,An image is worth 16x16 words: transformers for image recognition at scale,ViT。题目是说一张图片等价于很多16*16大小的单词。那为什么是16*16,而且为什么是单词?其实它是说把这个图片看作是很多很多的patch,就假如说我们把这个图片,然后打成这种方格的形式,每一个方格的大小都是16*16,那这个图片其实就相当于是很多16*16大小的这个patch组成的一个整体,接下来第二句是transformer去做大规模的图像识别。作者团队来自Google Research,Brain Team,接下来我们看一下摘要。
Abstract摘要 transformer现在已经是NLP自然语言处理领域里的一个标准,我们知道BERT,GPT3,然后或者是T5模型,但是用transformer来做CV还是很有限。在视觉里,这个自注意力要么是跟卷积神经网络一起用, 要么把某些卷积神经网络类的卷积替换成自注意力,还是保持整体的这个结构不变。我们说的这个整体结构是说譬如有一个残差网络ResNet50,它有四个stage ,res2,res3,res4,res5,那他就说这其实这个stage是不变,只是去取代每一个stage,每一个block里的这个操作。这篇文章证明了这种对于卷积神经网络的依赖,是完全不必要的。一个纯的transformer直接作用于一系列图像块的时候,它也是可以在图像分类这个任务上表现的非常好的,尤其是当在你在大规模的数据集去做预训练,然后又迁移到中小型数据集时候,这个vision transformer能获得跟最好的卷积神经网络相媲美的结果。作者这里把ImageNet,CIFAR-100,VTAB当做中小型数据集,但其实ImageNet对于很多人来说都已经是很大的数据集了。摘要的最后一句话,还指出了另外一个好处,他说transformer需要更少的这个训练资源。你乍样一听,觉得这真的很好,正筹手上两块卡或者四块卡训练不动大模型呢,这就来了一个需要特别少的训练资源就能训练的模型,而且表现还这么好。但其实你想多了,作者这里指的少的训练资源,是指2500天TPUv3的天数。他说的少,只是跟更耗卡的那些模型去做对比的,这个怎么说,还是比较讽刺,就跟某人说,我先定一个小目标,先赚一个亿。
Introduction引言 自注意力机制的这个网络,尤其是transformer,已经是自然语言处理里的必选模型。现在比较主流的方式,先去一个大规模的数据集上去做预训练,然后再在一些特定领域的小数据集上去做微调。那其实这个就是BERT这篇paper里提出来的。接下来说,多亏了transformer的计算高效性和这个可扩展性,现在已经可以训练超过1000亿参数的模型了,比如说像GPT3。然后最后一句话,他是说随着你的这个模型和数据集的增长,我们还没有看到任何性能饱和的现象。这个就很有意思了,因为我们知道,呃,很多时候不是你一味的扩大数据集,或者说扩大你的模型就能获得更好的效果的,尤其是当扩大模型的时候,很容易碰到就是过拟合的问题,那对于transformer来说,好像目前还没有观测到这个瓶颈。
在继续往下读引言之前,我想先说一下把transformer用到视觉问题上的一些难处,我们先来回顾一下transformer。
假如说我们有一个transformer,我们输入是有一些元素。假如说是在自然语言处理,这些就是一个句子里的一个一个的单词。输出也是一些元素,这里最主要的操作就是自注意力操作。自注意力操作就是说每一个元素都要跟每个元素去做互动,而且是两两互相的,然后算得一个attention。就是算得一个自助力的图,用这个自助力图去作加权平均,然后最后得到这个输出。因为在做自注意力的时候,我们是两两相互的,就是说这个计算复杂度,是跟这个序列的长度成翻倍的。目前一般在自然语言处理,就是说现在硬件能支持的这个序列长度,一般也就是几百或者上千,比如说在BERT,也就是512的这个序列长度。我们现在换到视觉领域,我们就是想用上transformer的话,首先第一个要解决的问题就是如何把一个2D的图片变成一个1D的序列,或者说变成一个集合。最直观的方式就是说我们把每个像素点当成元素,直接把2D的图片拉直,把这个扔到transformer里,然后自己跟自己学就好了。但是,想法很美好,实现起来复杂度太高。一般来说,在视觉里面,我们训练分类任务的时候,这个图片的输入大小,大概是224*224这么大,那如果把图片里的每一个像素点都直接当成这里的元素来看待,那其实它的序列长度,就不是512了。那它的序列长度就是224*224=50176,这序列的长度变成5万。其实也就意味着相当于是BERT序列长度512像100倍,所以这个复杂度是相当可怕,然后,这还只是分类任务,它的图片大小就224*24这么大,那对于检测或者分割这些任务,现在很多模型的输入,都已经是变成600*600,或者800*800或者更大了,那这个计算复杂度就更是高不可攀。所以说我们现在回到引言第二段,说在视觉里,现在卷积神经网络还是占主导地位的,像这AlexNet或ResNet,但是transformer在NLP领域又这么火,自注意力又这么香,那我计算机视觉,就是想用一下自注意力怎么办?所以说,很多工作就是想怎么能把自注意力用到视觉里来,一些工作,就是说去把这个卷积神经网络和自制力混到一起用。另外一些工作,就是说整个把卷积神经都换掉了,就全用自注意力。这些方法,其实都在干一个事儿,就是说你不是说序列长度太长,所以导致没办法把transformer用到视觉里来嘛,那我就想办法去降低这个序列长度。我们可以不用图片当transformer的直接输入,我们把网络中间的这个特征图当做传的输入,那大家都知道,假如说我们有ResNet50,那其实在它最后一个stage res4的时候,它的feature map size,其实就只有14*14那么大。那14*14的话,你把它拉平,其实也就只有196个元素,意思就是说这个序列长度,就只有196,这个就是可以接受的范围之内了。所以他用这种方式,用特征图当做transformer输入的方式去降低这个序列长度。第二个方向,有两个例子,一个叫做stand alone attention,另外一个是Axial attention,就是一个是孤立自注意力,一个是轴注意力。对于这个孤立自注意力,它做的什么事?既然这个复杂度高是来源于用整张图,那如果我现在不用整张图,我就用一个local的一个window,就我就用一个局部的小窗口,那这个复杂度就是你可以控制,你可以通过控制这个窗口的大小来让这个计算复杂度在你可接受的范围之内。这个就有点相当于回到卷积那一套操作,因为卷积也是在一个局部的窗口里做的。对于这个轴自注意力工作,它的意思是说图片的复杂度高是因为它的序列长度,是N=H*W,它是一个2D的矩阵,那我们能不能把图片这个2D矩阵拆分成两个1D的向量?所以先在高度上做一次自注意力,然后在宽度上再去做一次自助意力,相当于把一个在2D矩阵上进行自注意力操作,变成了两个1D的顺序的操作,那这样这个计算复杂度就大幅降低了。
他们虽然理论上是非常高效的,但事实上,因为他们的这个自注意力操作都是一些比较特殊的自注意力操作,没有现在的这个硬件去加速,很难把它训练成一个大模型。截止到目前为止,像这种stand attention,或者这个Axial attention,它的模型都还没有太大,就是跟这种百亿千亿级别的大模型比,还是差的很远,因此,最后一句话就是说在大规模的图像识别上这个传统的残差网络,还是效果最好的。那介绍完之前的工作,接下来就来讲vision transformer这篇paper到底做了什么事了,所以我们可以看到,自注意力早已经在计算机视觉里有所应用,而且甚至已经有完全用自注意力去取代卷积操作的工作,所以这篇论文,他就换了个角度去讲故事。他说,他们是被transformer在NLP领域里这个可扩展性所启发。他们想做的,就是直接应用一个标准的transform直接作用于图片,尽量做少的修改。就是不做任何针对视觉任务的特定改变,看看这样的transformer能不能在视觉领域里扩展的很大很好。如果直接用transformer,那老问题又回来了,这个这么长的序列长度该怎么办?这个vision transformer 是怎么处理的?vision transformer像我们刚才讲的一样,我把一个图片打成了很多patch,每一个Patch,就是16*16。我们来看,假如说这个图片的大小是2224*2224,那刚开始我们算sequence length,是224*224=50176,那现在如果我们换成patch,就是这一个patch,相当于是一个元素,那有效的长宽又会是多少?那比如说现在这个宽度变成了224/16=14了,同样的高度也就是14,所以说这样的话,最后的这个序列长度,就变成了14*14=196。意思就是说现在这张图片,就只有196个元素.
先看图
利用JDK(调用JAVA API)开发JAVA程序后,通过JDK中的编译程序(javac)将我们的文本java文件编译成JAVA字节码,在JRE上运行这些JAVA字节码,JVM解析这些字节码,映射到CPU指令集或OS的系统调用。
参考 1、https://blog.csdn.net/qq_42257666/article/details/105701938
做干洗店和洗鞋店的老板们很多都不止一个门店,多门店的管理模式下,去做一个上门洗衣洗鞋小程序,需要有哪些必要的功能才能让不同的门店管理起来不乱呢。首先需要先确定一下不同门店的管理都会面临哪些经营场景和需求。
第一,加盟店和直营店的区分,最主要就是账面上的区分,用户在平台充的钱,和用户在加盟门店充的钱要区分开,在平台充的钱可以在所有的门店去消费,订单完成系统自动分账,如果是在这个加盟店消费了,加盟店可以提现自己的服务收入。但是如果在加盟店门店内冲的钱,可能是直接给的现金,或者扫描经营者的收款码,就直接把资金给到经营者了,那么这些钱,就只能在这个加盟店去进行消费。而不能在其他的门店消费,大家可以捋一下这个逻辑哈。
再者就是,不同的门店位置决定了周边的消费水平的不同,所以门店服务产品的定价可能需要不一样,作为平台的管理者或者不同门店的经营者,可以按照所在商圈的消费水平去对产品的定价进行管理,各自决定门店的价格而非平台的统一定价。
这样的多门店多价格体系,实现起来并不难。
《A Byte Of Python》
中文《简明Python教程》本书采用知识共享协议免费分发,意味着任何人都可以免费获取,这本书走过了11个年头,最新版以Python3为基础同时也会兼顾到Python2的一些东西,内容非常精简,适合零基础入门,文末可下载电子版!
豆瓣评分:8.8
推荐指数:✩✩✩✩✩
《Head first Python》
中文《深入浅出Python》这本书的内容通熟易懂,配有大量插图,没有长篇累牍地说教,让你在学习过程中不会觉得枯燥,同为入门推荐书目。
豆瓣评分:8.3
推荐指数:✩✩✩✩
《父与子的编程之旅》
这并不是关于亲子关系的编程书,而是一本正儿八经Python编程入门书,只是以这种寓教于乐的形式阐述编程,显得更轻松愉快一些。
豆瓣评分:8.5
推荐指数:✩✩✩✩
《Effective Python》
本书可以帮你掌握真正的 Pythonic 编程方式,令你能够完全发挥出Python语言的强大功能,并写出健壮而高效的代码
豆瓣评分: 8.7
推荐指数:✩✩✩✩
《流畅的Python》
本年度最好的一本Python进阶书籍,从点到面、从最佳编程实践深入到底层实现原理。每个章节配有大量参考链接,引导读者进一步思考。
豆瓣评分:9.4
推荐指数:✩✩✩✩✩
《Python源码剖析》 深入Python底层原理,适合对Python实现原理感兴趣的开发者阅读。
豆瓣评分:8.7
推荐指数:✩✩✩✩
《集体智慧编程》
一本注重实践,以机器学习与计算统计为主题背景,讲述如何挖掘和分析Web上的数据和资源的书,本书代码示例以Python为主。入门人工智能的都应该看看这本书。
豆瓣评分:9.0
推荐指数:✩✩✩✩✩
《利用 Python 进行数据分析》
数据分析库 pandas 作者写的,数据分析入门就靠它了。
豆瓣评分:8.5
推荐指数:✩✩✩✩✩
最后 如果对Python感兴趣的话,可以试试我的学习方法以及相关的学习资料
Python所有方向的学习路线
Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。
二、Python必备开发工具
三、精品Python学习书籍 当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。
四、Python视频合集 观看零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。
五、实战案例 光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
六、Python练习题 检查学习结果。
七、面试资料 我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。
大家拿到脑图后,根据脑图对应的学习路线,做好学习计划制定。根据学习计划的路线来逐步学习,正常情况下2个月以内,再结合文章中资料,就能够很好地掌握Python并实现一些实践功能。
随着企业的快速发展,招采管理逐渐成为企业运营中的重要环节。为了满足公司对内部招采管理提升的要求,建立一个公平、公开、公正的采购环境至关重要。在这个背景下,我们开发了一款电子招标采购软件,以最大限度地控制采购成本,提高招投标工作的公开性和透明性,并确保符合国家电子招投标法律法规及相关规范。
项目说明
随着公司的快速发展,企业人员和经营规模不断壮大,公司对内部招采管理的提升提出了更高的要求。在企业里建立一个公平、公开、公正的采购环境,最大限度控制采购成本至关重要。符合国家电子招投标法律法规及相关规范,以及审计监督要求;通过电子化平台提高招投标工作的公开性和透明性;通过电子化招投标,使得招标采购的质量更高、速度更快。过招投标文件电子化,节约招标成本,提升企业的资金节约率。
开发类型
电子招标采购软件
解决方案
招标面向的对象为供应商库中所有符合招标要求的供应商,当库中的供应商有一定积累的时候,会节省大量引入新供应商的时间。系统自动从供应商库中筛选符合招标要求的供应商,改变以往邀标的业务模式。招采工作完成对供应商进行评分,对不合格供应商进行拉黑;供应商报名、缴费以及投标、答疑等过程通过系统自助完成。以往线下存档资料管理困难,回溯项目过程不清晰,回溯过程复杂,现在通过线上存档的方式,存档方便,可以快捷高效的对以往招采项目进行回溯。
一、立项管理
1、招标立项申请
功能点:招标类项目立项申请入口,用户可以保存为草稿,提交。
2、非招标立项申请
功能点:非招标立项申请入口、用户可以保存为草稿、提交。
3、采购立项列表
功能点:对草稿进行编辑,驳回的立项编辑,在途流程查看。
二、项目管理
1、采购计划管理
功能点:采购计划新增、编辑、删除
2、采购过程管理
功能点:查询、维护基准价、组建评审小组、项目答疑澄清、文件费保证金审核、供应商报价维护、查看评审明细。
3、招标代理机构抽取
功能点:招标代理机构抽取
4、造价机构抽取
功能点:造价机构抽取
5、线下项目管理
功能点:新增、导入、删除、编辑。
三、采购公告管理
1、项目公告查询
功能点:招标类公告创建、非招标类公告创建、查看、编辑、提交审核、停用。
四、评审管理
1、项目评审
功能点:查询、评审人员提交评分。
五、考核管理
1、项目考核分派
功能点:查询、查看详情、发布考核、指派考核负责人。
2、项目考核查询
功能点:查询、查看详情、分配考核人。
3、项目考核
功能点:查询、查看详情、提交考核评分。
六、供应商企业中心
1、投诉建议
功能点:提交投诉建议
2、企业信息
功能点:修改企业信息
3、项目管理
功能点:查看公告、查看项目、下载标书、缴纳文件费、缴纳保证金、上传标书文件。
七、招标代理机构企业中心
1、基本信息
功能点:修改企业信息
2、项目管理
功能点:查看项目详情及状态
3、公告管理
功能点:招标类公告创建、非招标类公告创建、查看、编辑、提交审核、停用。
该电子招标采购软件解决方案为企业的招采管理带来了显著的优化。它不仅满足了公司对内部招采管理提升的要求,还符合了国家电子招投标法律法规及相关规范。通过电子化平台,招投标工作的公开性和透明性得到了提高,使得招标采购的质量更高、速度更快。此外,通过招投标文件电子化,节约了招标成本,提升了企业的资金节约率。
一、主要有以下三种方法: 1、passwd命令,手动修改(passwd 用户名): (1)输入命令:passwd root
(2)输入新密码和重新输入新密码(由于linux输入密码时不显示,所以一定要保证两次输入密码相同):
2、passwd命令,命令行修改: (1)输入命令:
(2)密码修改成功:
3、chpasswd命令,命令行修改 (1)输入命令:
(2)密码修改成功:
4、注意: 由于linux所装系统不同,显示的结果也会有所不同,但三种方法博主试了大多是系统都试用。
二、passwd时报错passwd: Authentication token manipulation error 报passwd:Authentication token manipulation error错误是:密码身份验证令牌操作错误,一般是密码文件的权限的问题,也有可能是根目录空间满了。
用lsattr命令查看存放用户和密码的文件属性,发现有i选项(i:不得任意更动文件或目录),因为没有权限允许,所以导致所有的用户都不能修改密码。
要用chattr命令将i权限撤销,然后再修改密码。
[root@localhost ~]# lsattr /etc/passwd ----i--------e- /etc/passwd [root@localhost ~]# lsattr /etc/shadow ----i--------e- /etc/shadow [root@localhost ~]# chattr -i /etc/passwd [root@localhost ~]# chattr -i /etc/shadow [root@localhost ~]# lsattr /etc/shadow -------------e- /etc/shadow [root@localhost ~]# lsattr /etc/passwd -------------e- /etc/passwd [root@localhost ~]#
文章目录 1 前言2 概念介绍2.1 什么是图像语义分割 3 条件随机场的深度学习模型3\. 1 多尺度特征融合 4 语义分割开发过程4.1 建立4.2 下载CamVid数据集4.3 加载CamVid图像4.4 加载CamVid像素标签图像 5 PyTorch 实现语义分割5.1 数据集准备5.2 训练基准模型5.3 损失函数5.4 归一化层5.5 数据增强5.6 实现效果 6 最后 1 前言 🔥 优质竞赛项目系列,今天要分享的是
🚩 基于深度学习实现语义分割算法系统
该项目较为新颖,适合作为竞赛课题方向,学长非常推荐!
🥇学长这里给一个题目综合评分(每项满分5分)
难度系数:3分工作量:4分创新点:4分 🧿 更多资料, 项目分享:
https://gitee.com/dancheng-senior/postgraduate
2 概念介绍 2.1 什么是图像语义分割 这几年,随着深度学习理论和大规模并行计算设备快速发展,计算机视觉的诸多难点实现了质的突破,包括图像分类叫、目标检测、语义分割等等。
其中图像分类和目标检测在各种场景应用中大放光彩。目前最先进网络的准确度已经超过人类。
而图像语义分割是一.种语义信息更丰富的视觉识别任务,其主要任务是实现像素级别的分类。
图像语义分割示意图如下图所示。
图像语义分割技术在实际中有着非常广泛的应用,如自动驾驶、生物医学以及现实增强技术等等。
语义分割在自动驾驶的应用:
3 条件随机场的深度学习模型 整个深度学习模型框架下如图:
3. 1 多尺度特征融合 图像中的各类物体都以不同的形态出现, 用来观测它们的尺度也不尽相同, 不同的物体需要用合适的尺度来测量。
尺度也有很多种, 宏观上大的如“米”、“千米” 甚至“光年”; 微观上小的如“微米”、“纳米” 甚至是“飞米”。 在日常生活中,
人们也经常接触到尺度上的变换, 例如人们经常用到的电子地图上的放大与缩小、 照相机焦距的变化等,都是以不同的尺度来观察或者测量不同的物体。
当人们将一幅图像输入到计算机中时, 计算机要尝试很多不同的尺度以便得到描述图片中不同物体的最合适的尺度。
1. 需求 Nacos中关于中间件的密码,还有第三方API的密钥等信息,都是明文存储,不符合系统安全要求。现需对这些信息进行加密处理,Nacos只存储密文,并在服务启动时,调用云厂商的KMS接口进行解密,将解密后的明文存储在内存中供服务后续使用。
2. 组件调研&增强 2.1. jasypt 组件 业界上已有jasypt组件可以很好地支持对配置文件中的敏感信息进行解密处理,并完全支持 Spring Boot 架构。但是唯一的缺点是,该组件默认仅支持一些核心的静态加解密算法,无法支持接入第三方KMS;并且,仅支持对一个完整配置项的解密处理,不支持对配置项中某段字符串进行解密操作。因此,不能直接使用在我们已有的服务上。
2.2. 增强 我们需对上述组件进行增强,主要是以下两点:
配置项部分解密:支持解密配置项中指定的某段字符串,使用ENC()CNE括住第三方KMS解密:支持接入第三方KMS接口,对密文进行解密操作,支持将明文托管在KMS中(这里使用的是腾讯云的KMS) 我们不但要对jasypt组件进行增强,同时也需在此基础上再封装一个组件,用于整个平台的服务使用,避免冗余代码。
2.2.1. 引入相关依赖 核心是引入jasypt的 Spring Boot 组件,以及KMS(如腾讯云)组件:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>com.github.ulisesbocchio</groupId> <artifactId>jasypt-spring-boot</artifactId> <version>3.0.3</version> </dependency> <dependency> <groupId>com.tencentcloudapi</groupId> <artifactId>tencentcloud-sdk-java</artifactId> <version>3.1.927</version> </dependency> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.16.0</version> </dependency> 2.2.2. 启动配置解密注解 此注解作为服务引入KMS加密的钥匙,加了才会启动KMS解密功能:
/** * 开启kms配置密文解密 * @author winfun * @since 2023-12-18 **/ @Inherited @Component @Target(ElementType.
详情:智慧水务数字孪生安全监测解决方案提供商-星创 (key-iot.com.cn)
随着农业IOT的快速发展,智慧灌溉正成为提高农业水资源利用效率,实现精准灌溉的重要技术手段。完整的智慧灌溉系统由实地各类传感设备以及后台管理软件平台组成,可以实现对整个灌区的监测和精准控制,大大提高农业灌溉效率和产量。
一、灌区实地设备
(一)遥测监控终端RTU
这是实现现场数据采集和远程控制的核心设备,主要具有以下功能:
1. 收集各类传感器的数据,包括土壤湿度、温度、EC电导率、光照度等参数。
2. 根据指令控制水泵、电磁阀、自动调节装置等执行设备的启停状态。
3. 通过4G、WIFI等方式将数据传输到后台服务器。
4. 支持本地数据存储,保证数据安全。
5. 支持远程固件升级。
6. 工业级设计,IP65防护等级。
(二)土壤湿度传感器
这类传感器主要埋设在根区土壤中,测量不同层次的土壤含水量,用于判断灌溉时机。常见类型包括:
1. 电容式土壤湿度传感器:利用介质的介电常数测量土壤含水量。
2. 电阻式土壤湿度传感器:利用土壤导电性变化判断土壤湿度。
3. 热脉冲式土壤湿度传感器:通过热脉冲在湿土和干土中的传播时间差判断土壤湿度。
(三)土壤温度传感器
测量不同土层温度变化情况,用于分析土壤热环境,判断作物生长环境。常用的传感器包括热敏电阻式、热电偶式等。
(四)土壤电导率传感器
测试土壤溶液电导率,反映土壤盐分含量,用于判断土壤质量及灌溉水质。一般采用电极探针插入地下直接测量。
(五)气象环境监测设备
包括测量气温、湿度、光照、雨量等的参数,用于分析本地气候环境和灌溉需求。
二、智能化灌区管控软件平台
该平台实现对整个灌区的统一监控管理,具有以下功能:
1. 数据接收展示:接收各测点设备的数据,实时展示分布情况。
2. 多因子分析:对土壤、气象等多维数据进行关联分析。
3. 灌溉建议:根据数据智能判断当前每个区域的灌溉需求量。
4. 自动控制:根据需求 开启相应的水泵进行浇灌。
5. 灌溉历史记录:保存每次灌溉的详细记录,以便查阅。
6. 设备监控:监测各设备运行状态,出现故障时报警。
7. 用户管理:不同权限的用户可查看及操作不同数据。
8. 移动 APP 控制:用户可以通过手机 APP 查看监控信息并操作。
9. 开放接口:支持与其他农业管理系统对接。
三、系统应用效果
该套智慧灌溉解决方案融合了传感网、工控系统和管理软件三位一体,可实现对整个灌区的精细化管理,具有以下应用效果:
1. 更科学合理的灌溉制定,根据多参数实时计算每个区域的准确用水量。
2. 更及时高效的灌溉操作,自动对水资源进行优化配置调度。
3. 更精确的灌溉控制,实现对不同作物不同生长阶段的精准浇水。
4. 更低的用水和人工成本,降低农业灌溉运营支出。
5. 更安全环保的作物生产,减少化肥农药的使用。
首先看配置文件要读到map中的信息:
test: user: name: 张三 age: 25 phone: 13700000000 配置类
/** * 配置类 * 从配置文件中读取数据映射到map * 注意:必须实现set方法 */ @Configuration @ConfigurationProperties(prefix = "test") @EnableConfigurationProperties(UserMapConfig.class) public class UserMapConfig { /** * 从配置文件中读取的user开头的数据 * 注意:名称必须与配置文件中保持一致,后面会把前缀截去 */ private Map<String, Integer> user = new HashMap<>(); public Map<String, Integer> getUser() { return user; } public void setUser(Map<String, Integer> user) { this.limitSizeMap = user; } } 最后在业务代码里面注入UserMapConfig,就能使用了。
这样,我们就可以把配置文件中的数据以map形式读出来了,key就是配置信息最后一个后缀,value就是值。
在 2023 年的开源活动中,于强同学参加并负责了 Nydus 开源存储构建与分发支持课题的相关工作。
大家好!我是来自西北工业大学的于强,在开源之夏 2023 中报名参与了 Nydus 项目,并在导师的帮助下顺利完成了题目。通过此次活动,不仅对容器和镜像的底层技术有了更进一步的了解,也体验了如何开始参与一个开源项目。
Nydus GitHub:
https://github.com/dragonflyoss/nydus
1
关于 Nydus & Acceleration Service
1.1 Nydus
Nydus 镜像加速框架[1] 项目是 CNCF[2] 开源项目 Dragonfly[3] 的子项目,它是对 OCI 镜像格式的探索改进, Nydus 提供了容器镜像与多种数据的按需加载的能力,它已在生产环境支撑了每日百万级别的容器创建,将容器或代码包的端到端冷启动时间从分钟级降低到了秒级。Nydus 目前由蚂蚁集团、阿里云、字节跳动联合研发,也是 Kata Containers 与 Linux 内核态原生支持的镜像加速方案。
1.2 Acceleration Service 加速镜像格式和普通镜像格式不同,构建或转换步骤是必须的,可以使用 Buildkit[4] 从 Dockerfile 直接构建加速镜像,也可以使用 Nerdctl[5] 或 Nydusify[6] 转换工具。为了让 Harbor[7] 进一步支持用户透明地使用加速镜像, Harbor 的子项目 Acceleration Service[8] 诞生了,Acceleration Service 为 Harbor 提供了自动转换加速镜像的能力。
Acceleration Service 作为通用的加速镜像转换框架,提供了两种转换服务:
Acceld 是一个通过 Harbor Webhook[9] 扩展的服务,它是一个通用的加速镜像转换框架。当用户推送镜像时,Harbor 向该服务发送 Webhook 请求,通过其集成的 Nydus、eStargz[10] 等转换驱动完成镜像的转换。 AccelCtl 是一个 CLI 服务,指定源镜像后同样通过集成的转换驱动完成一次加速镜像转换。 Nydusify 是 Nydus 生态提供的工具,可用于转换、挂载、校验 Nydus 镜像,其中 Convert 子命令使用了 Acceleration Service 项目提供的 Go Package ,以实现从 Docker / OCI 镜像到 Nydus 镜像的转换。
蚂蚁集团多语言序列化框架 Fury 于 2023 年 7 月份正式开源,2023 年 12 月 15 号我们将 Fury 捐赠给 Apache 软件基金会 (Apache Software Foundation)。Fury 以 14 个约束性投票 (binding votes),6 个非约束性投票 (non-binding votes),无弃权和反对票,全票通过投票决议的优秀表现,正式加入 Apache 孵化器,开启新的旅程。
从写下第一行代码、到开源的实践,再到成功捐赠给 Apache 基金会,Fury 始终坚持认真开源,也始终相信项目带来的实际生产价值。加入 Apache 孵化器后,Fury 将持续保持「开放、协作」的社区共建方式,相信在基金会的帮助下,Fury 能和更多的开发者一起释放更大的技术能量,为大家提供更好的序列化框架。
Fury 简介
Fury 是一个基于 JIT 动态编译和零拷贝技术的多语言序列化框架,支持 Java/Python/C++/JavaScript/Golang/ Scala/Rust 等语言,提供最高 170 倍的性能和极致的易用性,可以大幅提升大数据计算、AI 应用和微服务等系统的性能,降低服务间调用延迟,节省成本并提高用户体验;同时提供全新的多语言编程范式,解决现有的多语言序列化动态性不足的问题,显著降低多语言系统的研发成本,帮助业务快速迭代。
Fury 发展历史
2019 年,Fury 作者杨朝坤写下第一版代码,用于蚂蚁集团内部在线机器学习引擎 Mobius 和实时计算引擎 Realtime 的 Java/Python 进程间序列化。
2020 年,Fury 在蚂蚁内部基于分布式计算引擎 Ray 的生态大规模落地。
2021 年,我们申请将 Fury 开源,考虑到当时 Fury 只有作者杨朝坤一个人在开发,出于项目长期可维护性角度先在内部开源构建社区。