QT之QGraphicsProxyWidget

文章目录 介绍例程 介绍 QGraphicsProxyWidget 是 Qt 图形框架中的类,它是 QGraphicsItem 的一个子类。这个类提供了一个方式来在 QGraphicsView 系统中嵌入自定义的 Qt 控件,而不需要直接从 QGraphicsItem 继承。 使用 QGraphicsProxyWidget 的主要优势在于它能够利用 Qt 的图形视图框架的所有功能,例如视图变换、场景和视图的互动、以及视图动画等。 以下是一些详细的用法: 1)创建和设置:你可以直接创建一个 QGraphicsProxyWidget 的实例,并通过 setWidget() 方法将其实例化,该方法接受一个 QWidget 类型的参数,你可以将需要嵌入的部件作为参数传入。 2)事件处理:QGraphicsProxyWidget 在两个对象之间转发事件,它不仅基于 QWidget 的整数型几何坐标,也基于 QGraphicsWidget 的浮点型几何坐标,进行转换。 3)功能支持:QGraphicsProxyWidget 支持 QWidget 的所有核心功能,包括Tab切换焦点、键盘输入、拖放和弹出窗口等。对于弹出窗口的处理,例如当嵌入的 QComboBox 显示其弹出列表时,会自动创建一个新的 QGraphicsProxyWidget ,嵌入弹出窗口并正确定位。 4)嵌套部件:你还可以嵌入复杂的小部件,例如带有子小部件的小部件。这些子部件也可以被代理,并嵌入到主部件中。 例程 #include <QGraphicsProxyWidget> #include <QGraphicsScene> #include <QGraphicsView> int main(int argc, char *argv[]) { QApplication a(argc, argv); QGraphicsScene scene; QGraphicsProxyWidget *proxy = new QGraphicsProxyWidget(); QWidget *widget = new QWidget(); widget->setFixedSize(200, 200); // 在 QGraphicsProxyWidget 中嵌入自定义控件 proxy->setWidget(widget); scene.

对 K8s 中的 NameSpace的ResourceList进行加减操作

背景 需要将命名空间内新家的STS所使用的配额自动加到NameSpace上, 就需要对NameSpace的ResourceList做加减操作 计算STS配额参考: https://blog.csdn.net/qq_21047625/article/details/134946922 将STS配额转为NameSpace的配额参考: https://blog.csdn.net/qq_21047625/article/details/135020443 代码 import ( v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" ) var ( nsLabelArray []v1.ResourceName = []v1.ResourceName{"requests.cpu", "requests.memory", "requests.storage", "requests.nvidia.com/gpu", "limits.cpu", "limits.memory"} ) func CalNsResourceList(data1 v1.ResourceList, data2 v1.ResourceList, calFunc func(resource.Quantity, resource.Quantity) resource.Quantity) (res v1.ResourceList) { res = v1.ResourceList{} for _, labelData := range nsLabelArray { req1 := data1[labelData] req2 := data2[labelData] resQuota := calFunc(req1, req2) if resQuota.CmpInt64(0) < 0 { resQuota.Set(0) } res[labelData] = resQuota } return } func AddNsResourceList(data1 v1.

【深度学习】目标检测,实例分割,语义分割 逐一对比

提问:目标检测,实例分割,语义分割,有什么区别? 目标检测(Object Detection),实例分割(Instance Segmentation)和语义分割(Semantic Segmentation)是计算机视觉领域中三个相关但有着不同任务和目标的问题。下面是它们的简要区别: 目标检测(Object Detection): 任务描述: 目标检测的任务是在图像或视频中定位和识别多个对象,并为每个对象提供边界框(Bounding Box)。输出: 输出是一组边界框,每个边界框都标识了图像中的一个对象,通常还包括对象的类别标签。 实例分割(Instance Segmentation): 任务描述: 实例分割不仅要求定位和识别对象,还需要为每个对象中的每个像素分配一个特定的标签,以区分不同的实例。输出: 输出是一组分割掩码,其中每个掩码对应于一个对象的实例,标识了对象的像素级别的位置。 语义分割(Semantic Segmentation): 任务描述: 语义分割的任务是将图像分成多个语义区域,每个区域具有相同的语义标签,即将图像中的每个像素分类为属于特定的类别。输出: 输出是一张图像,每个像素都被赋予一个语义类别标签。 总结: 目标检测: 关注在图像中检测和定位多个对象,输出是边界框和类别标签。实例分割: 不仅关注对象的定位和识别,还关注对象的像素级别分割,输出是每个对象的分割掩码。语义分割: 关注将图像分成多个语义区域,每个像素都被分配一个语义类别标签。 实例分割和语义分割 的区别 让我们通过更具体的示例来更详细地解释实例分割和语义分割之间的区别: 语义分割(Semantic Segmentation): 任务描述: 将图像中的每个像素分类为属于特定的语义类别。每个像素都被标记为图像中的一个对象或区域,但不区分这些对象或区域是否属于不同的实例。示例: 如果图像中有一只猫和一只狗,语义分割将为图像中的每个像素分配“猫”或“狗”的标签,但不区分它们属于不同的独立实例。 实例分割(Instance Segmentation): 任务描述: 除了对图像中的每个像素进行语义分割外,实例分割还需要区分不同对象的不同实例。这意味着为每个独立的对象分配一个唯一的标识,即使它们属于相同的语义类别。示例: 如果图像中有两只猫和一只狗,实例分割将为每只猫和狗分配不同的标识,并提供每个对象的像素级别分割。 总结: 语义分割: 关注对图像中每个像素进行语义分类,不区分同一语义类别内的不同实例。实例分割: 除了对图像中每个像素进行语义分类外,还区分不同对象的不同实例,为每个对象提供唯一标识。 目标检测和实例分割有啥区别? 目标检测(Object Detection)和实例分割(Instance Segmentation)是计算机视觉中两个相关但有着不同任务的问题。 目标检测: 任务描述: 目标检测的任务是在图像或视频中检测并定位多个对象,并为每个对象提供一个边界框(Bounding Box)。目标检测不区分不同对象的实例,只关注对象的存在和位置。输出: 输出是一组边界框,每个边界框表示图像中的一个对象,通常还包括对象的类别标签。 实例分割: 任务描述: 实例分割不仅要求检测和定位对象,还需要为每个对象的每个像素分配一个唯一的标签,以区分不同对象的不同实例。实例分割不仅提供对象的位置,还提供每个对象的像素级别的分割。输出: 输出是一组分割掩码,其中每个掩码对应于一个对象的实例,标识了对象的像素级别的位置。 总结: 目标检测: 关注在图像中检测和定位多个对象,输出是边界框和类别标签。不提供对象的像素级别分割。实例分割: 不仅关注对象的定位,还区分不同对象的不同实例,提供每个对象的像素级别分割掩码。 要区分两者的关键是,目标检测提供对象的粗略位置信息(边界框),而实例分割提供更详细的对象分割,包括每个对象的像素级别标签。 瑕疵检测,应该用哪一种? 瑕疵检测通常涉及到检测图像中的异常或缺陷。选择使用目标检测、实例分割还是语义分割取决于您的具体需求和问题的性质。以下是一些建议: 目标检测: 适用情况: 如果您希望检测图像中的多个不同类型的瑕疵,并为每个瑕疵提供边界框和类别标签。优点: 目标检测适用于多个对象的场景,每个对象可能具有不同的类别。这使得它对于检测图像中的多个不同类型的瑕疵非常有效。 实例分割: 适用情况: 如果您希望检测并精确分割图像中的每个瑕疵实例。优点: 实例分割适用于需要区分不同实例的场景。如果同一类型的瑕疵可以同时出现在图像中,并且您需要对它们进行独立的分析和处理,则实例分割可能是一个更好的选择。 语义分割:

嵌入式系统挑战赛题目----简单栈数据结构

一、题目要求 实现一个简单的栈数据结构。栈是一种后进先出线性数据结构,只能在一端进行插入和删除操作。请编写一个C语言程序,实现包括栈的初始化、入栈、出栈以及判断栈是否为空等基本操作。 请根据要求在begin、end间完成代码,不要改变代码中其他部分。 示例输入和输出: Is stack empty?No Popped element: 30 Is stack empty?No 二、程序代 #include <stdio.h> #include <stdbool.h> #define MAX_SIZE 100 typedef struct { int data[MAX_SIZE]; int top; } Stack; void initStack(Stack *stack) { stack->top = -1; // 初始化栈顶指针为-1 } bool isStackEmpty(Stack *stack) { ///Begin/// // 如果栈顶指针为-1,则栈为空 if(stack->top==-1) return 1; else return 0; End } bool isStackFull(Stack *stack) { return (stack->top == MAX_SIZE - 1); // 如果栈顶指针等于最大容量减1,则栈为满 } void push(Stack *stack, int value) { if (isStackFull(stack)) { printf("

Vue基于html2canvas和jspdf生成pdf文件,解决jspdf中文乱码及自动换行等问题

在做项目时有这么一个需求,需要将当前页面指定区域的内容导出pdf到本地。借助了两个插件分别是html2canvas.js和pdf.js来实现。使用过程中遇到的问题及解决方法 解决一些问题: 导出按A4纸大小排列预留页面边距的问题内容过多自动分页的问题直接使用jspdf中文乱码的问题直接使用jspdf文本自动换行的问题 安装依赖 将页面转换成图片 html2canvas 的作用就是根据 DOM 生成对应的图片。它的屏幕截图是基于 DOM 的,因此可能不会 100% 精确到真实的表示,因为它不会生成实际的屏幕截图,而是基于页面上可用的信息构建屏幕截图。 npm install html2canvas --save 将图片导出成PDF JSPDF是一个JavaScript库,用于生成PDF文档。它可以直接在浏览器中生成PDF,也可以通过Node.js在服务器端生成PDF。JSPDF具有高度的自定义性和可扩展性,可以用于各种PDF生成需求。 npm install jspdf --save 具体使用 1、页面中创建一个容器ref=“contenterPdf” <template> <div> <div ref="contenterPdf"> <img alt="Vue logo" src="../assets/logo.png" /> <div>JSPDF是一个用于生成PDF文件的客户端JavaScript库。它提供了简单易用的API,使得我们可以在浏览器端创建PDF文件。相比于服务端生成PDF文件,使用JSPDF可以避免服务端的压力,并且能够实现更多的交互与设计效果。基于JSPDF,我们可以生成包括图表、表格、文字、图片、图形等各种元素的PDF文档,同时也可以设置字体、颜色、边框等多种属性来调整文档的样式。</div> </div> <button @click="handleExport">导出PDF文件</button> </div> </template> 2、创建/utils/htmlToPdf.js文件 import html2canvas from "html2canvas"; import jsPDF from "jspdf"; export const downloadPDF = page => { html2canvas(page, { useCORS: true, //允许canvas画布内 可以跨域请求外部链接图片, 允许跨域请求。 allowTaint: true, //允许跨域 scale: 2, 设置放大倍数 backgroundColor: '#ffffff'//背景色 }).

大数据毕业设计:Python电影数据采集分析可视化系统✅

🍅大家好,今天给大家分享一个Python项目,感兴趣的可以先收藏起来,点赞、关注不迷路,大家在毕设选题,项目以及论文编写等相关问题都可以给我留言咨询,希望帮助同学们顺利毕业 。🍅 1、项目介绍 Python语言、Flask框架、MySQL数据库、Echarts可视化、网络爬虫技术、豆瓣电影数据、requests爬虫框架、HTML 基于Flask电影数据采集可视化系统是一款利用Python的Flask框架,对电影相关数据进行采集、整理和可视化展示的应用系统。 2、项目界面 (1)系统首页----数据概况 (2)电影数据 (3)电影拍摄地点分析、电影语言分析 (4)评分分析、豆瓣评分星级、年度评价评分分析 (5)电影时长分布、电影数量统计分析 (6)电影类型饼图 (7)词云图分析 (8)数据采集爬虫 3、项目说明 基于Flask电影数据采集可视化系统是一款利用Python的Flask框架,对电影相关数据进行采集、整理和可视化展示的应用系统。以下是该系统的主要介绍: 数据采集:系统利用网络爬虫技术,从电影相关网站上获取电影信息。这些信息包括电影名称、导演、演员、评分、票房、发行日期、类型等。用户可以根据个人需求,设置搜索的关键词、时间范围、地区限制等参数,以获取感兴趣的电影信息。 数据处理:系统对采集到的电影数据进行清洗、整理和转换,以确保数据的准确性和一致性。包括处理缺失值、异常值和重复值,进行数据格式转换等操作。 数据可视化:系统使用Python中的数据可视化库(如Matplotlib、Seaborn等),将电影数据以图表、图形等形式直观地展示出来。包括电影类型分布、票房排行榜、评分分布等。同时,用户可以根据自己的需求进行图表的定制和设置,以满足个性化的展示需求。 用户交互:系统提供友好的用户界面和交互设计,用户可以搜索、排序、过滤,选择不同的时间范围、地区、类型等维度,获取感兴趣的数据和分析结果。用户还可以根据展示效果进行图表的调整和定制。 数据分析:系统还可以利用Python中的数据分析库(如Pandas等),对电影数据进行统计和分析,例如:评分和票房之间的关系,不同类型电影的市场占比,不同导演或演员的平均评分等。这些分析结果可以帮助用户更全面地了解电影市场的状况和变化。 综上所述,基于Flask电影数据采集可视化系统是一款利用Python技术进行开发的应用系统,旨在通过数据可视化和分析提供电影市场的信息和趋势。该系统可以帮助用户更直观地了解电影市场的情况,同时也对电影从业者、研究人员等提供有价值的参考信息。该系统通过友好的用户界面和交互设计,使得用户可针对个人需求进行定制,是一款十分实用的电影数据可视化工具。 4、部分代码 import json from flask import Flask,request,render_template,session,redirect import re from utils.query import querys from utils.homeData import * from utils.timeData import * from utils.rateData import * from utils.addressData import * from utils.typeData import * from utils.tablesData import * from utils.actor import * from word_cloud_picture import get_img import random app = Flask(__name__) app.

Mapreduce小试牛刀(2)--java api

1.同hdfs 的java api,我们首先要在IDE中建立一个maven项目 pom.xml中配置如下: <dependencies> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-mapreduce-client-common</artifactId> <version>3.3.4</version> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-mapreduce-client-jobclient</artifactId> <version>3.3.4</version> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-client</artifactId> <version>3.3.4</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.30</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <scope>test</scope> </dependency> </dependencies> --------------------------------------------------------------------------------------------------------------------------------- 2. 编写java 代码,重写map与reduce类(我们以最经典的wordcount为例) 第一步,建立java目录,建立一个叫test的包(可写可不写,看自己喜好) 第二步,导入hadoop包,以及其他所需的包 package test; import java.io.IOException; import java.util.*; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.*; import org.apache.hadoop.mapred.*; 第三步,重写map,resuce方法 1.map方法,目的在于切割文章内容为一对对键值对,实现map-reduce中的map过程 class Map extends MapReduceBase implements Mapper<LongWritable, Text, Text, IntWritable> { //前两个为输入类型,第一个数据类型表示首行偏移量;后两个为输出类型,输出为键值对类型 private final static IntWritable one = new IntWritable(1); //IntWritable实例对象初始化为1 private Text word = new Text(); public void map(LongWritable key, Text value, OutputCollector<Text, IntWritable> output, Reporter reporter) throws IOException { String line = value.

mybatisPlus属性自动填充配置之MetaObjectHandler接口实战

前言:在我们向数据库插入一条数据的时候,少不了一些向createTime、updateTime此类字段,每次插入的数据都要设置这些个值,很烦,通过实现MetaObjectHandler接口重写insertFill、updateFill方法可以帮你摆脱烦恼 本文概括 MetaObjectHandler介绍1:编写MetaObjectHandler 实现类2:实体类上边加上@TableField(fill = FieldFill.INSERT_UPDATE)注意点小节代码链接小咸鱼的技术窝 MetaObjectHandler介绍 MetaObjectHandler接口是mybatisPlus为我们提供的的一个扩展接口,我们可以利用这个接口在我们插入或者更新数据的时候,为一些字段指定默认值。实现这个需求的方法不止一种,在sql层面也可以做到,在建表的时候也可以指定默认值。 1:编写MetaObjectHandler 实现类 编写类实现MetaObjectHandler接口,重写里面的方法就是了。 /** * @author 张子行 * @class mybatisPlus属性自动填充,对应的实体类字段上需要加@TableField(fill = FieldFill.INSERT_UPDATE) */ @Configuration @Slf4j public class autoFillConfig implements MetaObjectHandler { /** * @param * @method 插入时自动填充 */ @Override public void insertFill(MetaObject metaObject) { log.info("插入时自动填充"); this.setFieldValByName("stock", 1, metaObject); } /** * @param * @method 更新时自动填充 */ @Override public void updateFill(MetaObject metaObject) { log.info("更新时自动填充"); this.setFieldValByName("stock", -9090, metaObject); } } 2:实体类上边加上@TableField(fill = FieldFill.INSERT_UPDATE) 指定进行属性填充的时机(更新、插入、或者更新和插入)

[转]实现透明Panel控件

原文:实现透明Panel及控件置顶的方法 我只是简单转换为VB以及对一些参数的微软出处作了补充(搜索了一下,发现这篇是最简洁、明了、可行的),有了这个重写的Panel,以后在进行自动操作中为了防止用户点击鼠标时,再也不用麻烦了。 ------------------------------------------------------------------------------------------------------ 想放置一个透明Panel在某控件上端,实现效果是可透过此Panel看见下面控件,但鼠标点击却无任何反应。 1、新建置自定义Panel类 Imports System Imports System.Collections.Generic Imports System.Linq Imports System.Text Imports System.Windows.Forms Imports System.Drawing Namespace NavDataManager Public Class MyTransparentPanel Inherits Panel Public Sub New() Me.SetStyle(ControlStyles.SupportsTransparentBackColor Xor ControlStyles.Opaque, True) Me.BackColor = Color.Transparent End Sub Private Const WS_EX_TRANSPARENT = &H20 Protected Overrides ReadOnly Property CreateParams() As CreateParams Get Dim cp As CreateParams = MyBase.CreateParams cp.ExStyle = WS_EX_TRANSPARENT Return cp End Get End Property End Class End Namespace '将控件添加到你需要放置的某控件上,并通过BringToFront与SendToBack来控制是否响应鼠标。 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.

QT之QMessageBox的用法

QT之QMessageBox的用法 成员函数用法举例 成员函数 QMessageBox是Qt框架提供的一个用于显示消息对话框的类。它提供了多种成员函数,可以用于设置对话框的内容、按钮和样式等。下面将详细介绍一些常用的QMessageBox成员函数: 1)setText(const QString &text):设置消息文本,参数text是要显示的文本内容。 2)setWindowTitle(const QString &title):设置对话框的标题,参数title是要显示的标题文本。 3)setIcon(QMessageBox::Icon icon):设置对话框的图标,参数icon是图标类型,可以是1)1)QMessageBox::Information、QMessageBox::Warning、QMessageBox::Critical等常量之一。 4)setStandardButtons(QMessageBox::StandardButtons buttons):设置对话框的标准按钮,参数buttons是按钮类型,可以是QMessageBox::Ok、QMessageBox::Cancel、QMessageBox::Yes、QMessageBox::No等常量之一或它们的组合。 5)exec():显示消息框,并等待用户做出选择。返回值是用户选择的按钮值,可以用于判断用户选择了哪个按钮。 6)showMessageDialog(QWidget *parent, QMessageBox::Icon icon, const QString &title, const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::NoButton, 1)QMessageBox::StandardButton defaultButton = QMessageBox::NoButton):显示一个简单的消息对话框,参数parent是对话框的父窗口,icon是图标类型,title是标题文本,text是消息文本,buttons是标准按钮类型,defaultButton是默认按钮类型。 7)addButton(const QString &text, QMessageBox::ButtonRole role):添加一个自定义按钮到消息框中,参数text是按钮显示的文本,role是按钮的角色,可以是QMessageBox::ActionRole、QMessageBox::YesRole、QMessageBox::NoRole等常量之一。 8)addStandardButton(QMessageBox::StandardButton button):添加一个标准按钮到消息框中,参数button是按钮类型,可以是QMessageBox::Ok、QMessageBox::Cancel、QMessageBox::Yes、QMessageBox::No等常量之一。 9)setLayout(QLayout *layout):设置消息框的布局,参数layout是一个布局对象,可以使用布局管理器来创建自定义的布局。 10)setStyleSheet(const QString &styleSheet):设置消息框的样式表,参数styleSheet是样式表字符串,可以使用CSS语法来设置对话框的样式。 用法举例 1)添加按钮: msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); 这里使用了按位或操作符来组合标准按钮。可以使用以下常量之一或它们的组合: QMessageBox::Ok:确定按钮 QMessageBox::Cancel:取消按钮 QMessageBox::Yes:是按钮 QMessageBox::No:否按钮 QMessageBox::Abort:中止按钮 QMessageBox::Retry:重试按钮 QMessageBox::Ignore:忽略按钮 if (result == QMessageBox::Ok) { // 用户选择了确定按钮,执行相应的操作 } else if (result == QMessageBox::Cancel) {

普通用户无法su到root用户的解决方法

今日在使用普通用户登录后切换root账号遇到问题,在切换root账号时输入正确的密码但提示无权限: [4a@hljydywfzcsxt1-5 ~]$ su - root Password: su: Permission denied 经过测试使用正确的密码可以直接登录root账号,这说明我们的密码没有问题。问题应该出在这个普通账号的设置上。 在网上查询各种资料后发现这与这台主机做了安全设置有关系。 问题在于设置PAM模块,PAM(Pluggable Authentication Modules)负责系统中很多应用程序的登录认证,包括sshd、vsftpd、su等。例如ssh登录认证配置文件是/etc/pam.d/sshd用户可根据需要配置相应的认证规则。你也可以为自己的其他应用配置PAM认证。 查看/etc/pam.d/su文件,我们可以发下有这么一行 auth sufficient pam_wheel.so trust use_uid 这就是控制普通用户是否可以进行su操作的选项。 解决方法有2种: 1、登录root账号,输入usermod -G wheel 用户名 将无法su的普通用户加入到wheel组 2、将auth sufficient pam_wheel.so trust use_uid 这一行注释掉。 例如#auth required pam_wheel.so use_uid

微信小程序识别小程序码并传参

一、场景 连续看到几个类似关于小程序生成二维码场景的问题,分销的场景和单商品购买的页面居多 二、思路 步骤 1 步骤 2 步骤3 步骤4 后端生成小程序码 前端通过接口获取到小程序码 前端展示小程序码 扫码识别进入页面 结束 服务端获取小程序码的文档相关链接 三、注意事项 后端添加的参数我们可以在onLoad中接收scene,记得使用decodeURIComponent解析 Page({ onLoad (query) { // scene 需要使用 decodeURIComponent 才能获取到生成二维码时传入的 scene const scene = decodeURIComponent(query.scene) } })

pako是什么以及它的的使用

文章目录 pako的作用使用 pako的作用 ws推送的gzip压缩能减少大量的传输数据,减少传输数据消耗,但是需要在收到数据之后解压。 解压就可以用到pako了 使用 npm install pako function (msg) { let reader = new FileReader() reader.readAsBinaryString(msg) // blob reader.onload = function () { result = JSON.parse(pako.inflate(reader.result, { to: 'string' })) // 打印出返回的数据 console.log(result) } }

Vue3报错: ‘defineProps‘ is not defined,解决方法

问题出现: 今天在使用 <script setup>组合式 API 的语法糖的时候,定义defineProps时候报错: ‘defineProps’ is not defined 查了一下资料,这是因为eslint的语法校验导致的问题。 解决方法1: 在项目根目录的文件.eslintrc.js中做如下配置: 添加配置:"vue/setup-compiler-macros": true,配置完之后需要重启项目,即可解决。 解决方法2: 如果你的项目根目录下没有.eslintrc.js文件,那就找到package.json文件 找到eslintConfig配置项,在这里配置规则:"vue/setup-compiler-macros": true,

弹性架构:容错系统策略

如今软件无处不在 - 从我们的手机到汽车和电器。这意味着软件系统的可靠性、健壮性和弹性非常重要。 弹性系统可以承受故障或错误而不会完全崩溃。容错能力是弹性的关键部分。即使出现问题,它也能让系统保持正常工作。 在本文中,我们将了解为什么弹性和容错能力对业务很重要。我们还将讨论构建容错系统的核心原则和策略。这包括冗余、故障转移、复制和隔离等内容。此外,我们将研究不同的测试方法如何识别潜在问题并提高弹性。最后,我们将讨论弹性系统设计的未来。云计算、容器和无服务器平台等新兴趋势正在改变弹性系统的构建方式。 韧性的重要性 系统故障可能会损害业务和技术运营。从业务角度来看,中断会导致收入损失、声誉受损、客户不满意以及竞争优势丧失。例如,2021 年,Reddit、Spotify 和 AWS 等主要在线服务宕机了几个小时。这次中断造成了数百万美元的损失,也让用户感到沮丧。同样,2021 年的一次维护错误导致 Facebook 及其服务在全球范围内中断约六个小时。数十亿用户和广告商受到影响。 在技术方面,系统故障可能会导致数据丢失或损坏、安全漏洞、性能问题和复杂性。例如,2020 年 Garmin 遭受勒索软件攻击,扰乱了其在线服务和健身追踪器。最近,即 2023 年,人为因素导致澳大利亚的 Microsoft Azure 服务器出现严重中断。 因此,构建弹性和容错系统至关重要。这样做可以防止或最大程度地减少系统故障对业务和技术运营的影响。 了解容错系统 即使出现问题,容错系统也能保持正常工作。故障是导致系统行为与预期不同的任何问题。故障可能是由硬件故障、软件错误、人为错误或断电等环境因素引起的。 在具有大量服务和子服务、数百台服务器并分布在不同数据中心的复杂系统中,小问题总是会发生。这些问题一定不能影响用户体验。 构建容错能力的三个主要原则: 冗余- 出现故障时可以接管的额外组件。故障转移 - 当检测到故障时自动切换到备份组件。复制 - 创建服务器或数据库等组件的多个相同实例。 消除单点故障至关重要。系统的设计必须确保没有任何单个组件对运行至关重要。如果该组件发生故障,系统可以通过冗余和故障转移继续工作。 这些原则使得容错系统能够检测故障、解决故障并在故障发生时进行恢复。这增加了整体弹性。通过避免过度依赖任何一个组件,可以提高整个系统的可靠性。 构建弹性系统的策略 在本节中,我们将讨论容错系统的三个原则中的每一个,并提供有效使用它们的系统示例。 冗余 冗余涉及拥有备用或替代组件,以便在出现故障时可以接管。它可以应用于硬件、软件、数据或网络。优点包括提高可用性、可靠性和性能。冗余消除了单点故障并实现了负载平衡和并行处理。 示例:负载平衡的 Web 应用程序 该 Web 应用程序在 3 个区域的 20 台服务器上运行 全局负载均衡器监控每台服务器的健康状况 如果美国东部的 2 个服务器发生故障,平衡器会将流量路由到美国西部和欧洲的其余服务器 避免单一区域故障可提供连续的正常运行时间 故障转移 故障转移机制检测故障并自动切换到备份。这可以保持连续性、一致性和数据完整性。故障转移允许在发生故障后顺利恢复操作。 示例:无服务器视频编码 媒体编码功能在 AWS Lambda 等无服务器平台上运行 平台跨多个可用区 (AZ) 自动扩展实例 可用区故障会禁用这些功能实例 其他实例在剩余可用区中启动以处理负载 故障转移提供弹性编码能力 复制 复制涉及在多个位置维护数据或软件等资源的相同副本。它提高了可用性、耐用性、性能、安全性和隐私性。

前端播放大视频卡顿的解决(m3u8视频流)

前言 最近在一个大屏看板项目中有一个需求是:要求视频和看板要进行来回切换。 最开始的做法是将MP4视频放在项目里,在本地运行时是没什么问题的,但是在往仓库里提交代码时出现了问题。当单个文件超过100MB时会导致代码提交失败; 后来的解决方案是将视频文件放到服务器上,项目里直接加载视频在服务器上的地址。但是这样也存在一个问题,就是视频加载会卡顿。video标签是边加载边播放,这样造成了视频播放几秒后会加载视频导致视频卡住,影响实际效果。 查询到的解决方案是将mp4视频转换成m3u8视频流的格式进行播放,因此打算尝试一下。下面会分别介绍: 1、将mp4视频转换为m3u8视频流 2、前端如何播放m3u8视频 将mp4视频转换为m3u8视频流 m3u8格式 m3u8是苹果公司推出的视频播放标准,是m3u的一种,只是编码格式采用的是UTF-8。M3U文件是一个记录索引的纯文本文件,打开它时播放软件并不是播放它,而是根据它的索引找到对应的音视频文件的网络地址进行在线播放。 方法/步骤 主流的方式是通过 m3u8格式视频转码工具 FFmpeg 来实现的 下载 从网上找了个百度云下载地址:https://pan.baidu.com/s/1dCK-TrOcUfC6pdKi2Y1e6g 提取码:2pdo 下载完解压后可以在bin文件嘉下看到三个可执行文件,配置好相应的环境变量后即可使用 环境变量配置 在cdm终端里输入:ffmpeg -version,如下图表示安装成功。 常用命令 ffmpeg 常用命令 分割视频 在视频所在的文件夹下打开cmd终端,输入: ffmpeg -i video1.mp4 -profile:v baseline -level 3.0 -start_number 0 -hls_time 1 -hls_list_size 0 -f hls demo.m3u8 -i 指定输入的文件名 -profile:v baseline 大概意思是档次转成基本画质,有四种画质级别,分别是baseline, extended, main, high,从低到高 -level 3.0 大概也是视频画质级别吧,基本上是从1到5, -start_number 0 表示从0开始 -hls_time 1 标识每1秒切一个 -f hls 将视频转为hls格式 -hls_list_size 0 ,设置播放列表保存的最多条目,设置为 0 会保存有所片信息,默认值为5。 其他的命令不清楚,需要什么功能,基本都可以百度到

Django 表单处理:从前端到后台的全流程指南

概要 Django作为一个高级Python Web框架,它的表单处理能力强大,可以有效地处理用户输入,进行数据验证以及错误处理。本文将详细介绍如何在Django中创建、处理和使用表单。 1. Django表单系统的核心 Django的表单系统处理表单的生命周期,涉及以下核心部分: 表单类:定义表单的结构和行为。 验证逻辑:确保提交的数据满足特定条件。 模板:展示表单的HTML表述。 视图:处理表单的提交过程,包括数据的验证和处理。 2. 创建表单类 Django的forms模块提供了一个灵活的表单类,你可以定义自己的表单类来表示一个HTML表单。 from django import forms class ContactForm(forms.Form): name = forms.CharField(max_length=100) email = forms.EmailField() message = forms.CharField(widget=forms.Textarea) 3. 在视图中处理表单 在Django视图中,你需要处理GET和POST请求。GET请求通常用于展示空表单,而POST请求处理表单提交的数据。 from django.shortcuts import render from .forms import ContactForm def contact_view(request): if request.method == 'POST': form = ContactForm(request.POST) if form.is_valid(): # 处理表单数据 return redirect('success_url') else: form = ContactForm() return render(request, 'contact.html', {'form': form}) 4. 表单的验证 Django提供了一个强大的表单验证系统。在调用is_valid()方法时,Django会进行数据清洗并运行所有的验证器。 if form.is_valid(): # 这里的cleaned_data是验证后的数据 name = form.

没做开发的日子都在干什么?

事件起始 今年公司做出了两轮的人员调整,分别是4月和10月,每次的调整的原因都是一样的,由于公司的业务没有利润,所以上层做出了相关的人员调整,然后就是留下的员工就会被叫到一间办公室里面开会,说一下我们接下来要做的事情,然后要让我们充满信心,只要我们盈利,大家的努力都会在薪资上有一个提现。 而我就是天选之子,我“幸运”的被留了下,离职的同事理所应当的拿到了离职赔偿,第一轮的人员调整,在这里也就落下帷幕,留下的同事还有一起继续奋斗,这时虽然人少了,但是业务还在,所有我将我负责的小程序部分后续的功能陆续完善,当功能完善了,这个项目就已经结束了,小程序就没有被投入到生产的环境中去使用,就这样闲置了。 旅游项目 后来公司谈下了一个旅游的项目是做出国游的,当时想着疫情结束的第一年,然后天气也正当时,所以感觉这个项目应该很容易就会成功,而且这个项目是和一个知名的旅游企业合作的,因为有自己的直播团队,所以直播团队很快的就落地了方案,开启了旅游的直播。 我们也针对旅游的直播去做相关的活动策划,再把以前的小程序拿过来增加了分销活动的入口,因为想着旅游如果你能邀请新人给你返现,后续设计了围绕这个活动又设计很多,包括海报页,但是当一切都设计好了以后,又这样被闲置了起来,直播团队也还在直播,但是基于我们开发的东西又石沉大海,好像又做了一堆没用的功能。 内部系统及问题 在开发旅游项目活动的时候,突然来了一个公司内部的项目,是个迭代系统,主要功能就是:让公司的员工,将工作分为事项,然后将每周的工作进度和工作任务填写到里面,方便领导查看,也可以让其他员工看到你在进行的事项,也做“自我监督”,犹豫人员调整的影响公司并没有了产品经理,所有我和开发的同事,一起根据领导的需求,来落地这件事情,画原型(此处省略1w字…),然后再一次次沟通了N遍后,终于有了产品雏形,然后让ui设计出来,接下来我们进行了无休止的加班时刻。 大概1周多整个基础版的功能就出来了,在这里我尝试使用了taro去写的H5,功能简单,所以想做一些新的尝试,用了react,这里面遇到了很多的问题: 如taro本身的轮播图在H5企微环境下,进入页面直接跳入第二张图片;后来使用了Taro UI的轮播图,解决了这个问题在ios,企业微信浏览器下,跳转页面回退后,会闪一下当前的页面(至今仍未解决,在github提了leusse,给的原因是:应当是动画导致的,可以关闭跳过该问题)还有react本身的问题,而且是一些基础的问题,useSate 是异步更新的,在接口获取的时候老是set完后拿不到值,要不使用useEffect,要不就是单独使用useRef进行定义 因为是基于企业微信,所以我们上线后在内部先做测试,测试完后,我们迅速得到了反馈: 然后我们再次梳理流程,修改里面的功能,几乎是重构了现有的,在代码了的层面上做了一个大的迭代,下图就是功能了,主要是记录,像个记事本一样,依托于企微: 功能完成后,进行在公司投放使用了,过了一段时间,也没有人再在这个上面去迭代自己的事项了,这个内部的项目也算是结束了,但是在这个项目里因为使用了自己以前没有接触过的技术,所以对自己来说是收获满满的一个项目。 尝试AI 公司不会因为一个项目的失利或者不行就会放弃,这个时候公司关注到了AI大模型,我们也有自己的核心项目SCRM的项目,所以公司当时想着要用大模型助力我们的项目,我们开始去看大模型相关的知识,langchain,chatglm-6b,chantgpt,想着训练一个自己的模型出来,发现难度很大,就又找了公司合作,基于人家的星火大模型,让合作的攻速去训练一个本地知识库,期间我们只需要写一个聊天室的功能接入API就行,然后他基于你给的文档回复相关的问题,然后就需要慢慢训练就好了,当时持续了一段时间,这个训练的计划就不告而终了,可能是不满意训练的效果,也可能有其他的问题,这就不得而知了,在这期间也是大概了解了gpt的工作原理,对自己也算是一个小小的进步吧。 海外产品 公司谈下的另一个项目也落地了,是个海外保健品的项目,货已经到公司了,然后公司召集同事开了一个内购会,会间介绍了这个里面的产品,当时感觉这个产品就感觉很高端,虽然是白牌、单价还很高、但是名字听起来就很高端,产品定了,后续的开发也就要陆陆续续的进来了。 果然没长时间,我接到了SCRM管理SOP模块的需求,这个需求业务逻辑很多,大概有两个多星期才写完,然后又写了个分销的小程序页面,因为跨境保健品的特殊需求,所以我们借助有赞才有资质进行售卖,在这期间还有很多其他的事情,如有赞页面的搭建、商品的上下架、活动的创建,对应的官网页面也在开发,这个时候公司开始决定招人,于是我的工作项开始了招人,开始面试,面试的人很多,也有合适的,但是不知道为什么没有入职的同学。 过了一段时间我的SOP开发完成了,我的分销小程序也开发完成了,后续就是微信小程序就要备案,备案的时间很长,大概在两周多的时间,期间内准备了很多的材料,就在感觉以前都会按照现在的工作计划进行的时候,肯定因为具体在线上推广的难度比较大,一直没有用户进来,没有用户基础,也没有找到解决的办法,所以导致我们的系统起不到什么作用,我们的项目需要有用户基础的。 虽然没有用户基础,但是开发的功能也一直在推进,也做着一些感觉有用的功能,就往系统里面加,直到10月中旬,我们迎来了第二次的人事调整,还是在4月听过的一些话,又重复的说了一遍。 再次调整 那我再次被通知留了下来,那后续的工作是关于直播数据分析相关的工作和代码再无瓜葛,也不是完全不写,就是可能代码会辅助现在所做的工作,上班三件套从 vscode、微信开发者工具、chrome 变成了 wps、微信、chrome,这次的工作变动也是感触颇深,虽然目前的工作没有写代码,但是也不会一下子就全忘了,但是要温故而知新,所以也会每天看看小程序的公告看看有什么新的更改,也会看一些nest和vue3相关的知识。 直播运营 新的工作内容朋友们也可以理解为直播运营,为直播团队提供数据支持。 相关的文章也是收藏了很多,如果有想尝试直播的可以去抖音电商学习中心看看。 从零开始学习直播是很快的,而且抖音的文档中也有很多的文档支持,但是也有很多假大空的内容,就是那种道理你都懂,但是执行起来却很难,不知道是不是因为学的太浅的原因,感觉如果一个直播间的成功不仅仅是靠投流、或运营支持,主播的发挥、可能还有一部分运气的存在。 这是梳理的直播间的搭建,大概就是按照这个框架去走的,直播间的流程设计方向,这期间也写了很多如何落地的方案,分析了很多直播的话术、和直播间的场景、以及投放计划的方案。 在挖掘数据中,用到了很多的第三方的网站: 有米有数 数据全,价格高考古加 数据一般,价格便宜蝉妈妈 数据全,价格高达多多 数据一般,价格便宜巨量算数 官方产品,数据挖掘巨量创意 官方产品,数据挖掘巨量千川 官方产品,抖音投放抖音罗盘 官方产品,直播数据 在这期间认识到不同投放针对的不同场景: 抖+ 针对单个视频热度进行加热小店随心推是简易版的千川投放,针对的是没有做过投放,我没有专业投放人员的商家巨量千川 专业的投放平台、可以投直播间画面、短视频广告巨量广告 可以投游戏广告、开屏、应用推广、cid(点击跳转到其他的app) 经过了团队大约两个星期的讨论,终于形成了一个完整的方案,接下来我们调试了直播设备,然后开播了,第一天带货有了成交,大家都很开心,感觉开门红,然后投放那边流量跑的也还不错,自然流量进来的也不少,但是第二天效果就不太好了,可能是因为在直播期间调整了直播间的一些元素,影响了直播间的进人,然后我们迅速开会讨论,因为在讨论直播方案期间,我们一直有一个竞品直播间,他们卖的很好,后来了解到他们每天的投放的金额是很多的,所以和人家不在一个量级上。 然后就这样播了三天,然后就停掉了,可能就是为了测试一下能不能行,可惜的是我们并没有在坚持一个小周期,这样就可以看到为什么会这样,也有可能因为其他的专业的直播团队以前播过同样的品,效果不好,而我们只是再试试看看我们这些对直播没有一点了解的,能不能出现奇效,不过很快就被现实的状况打败了,现在回想起来好像直播真不是什么人都能播的,面对寥寥无几的观众播6,7个小时也挺累的。 !](https://img-blog.csdnimg.cn/direct/69fedea807b74deaa14c8baa15b8d9a1.png) 在线问诊 直播终止掉后(只是我们不播了,交给人家专业的团队播了),新的合作项目也谈的差不多了,随之而来的是需要开发新的功能去兼容人家的系统,所以准备告别的同事也暂时的留了下来,他们签了一个三个月期限的协议,而我也从前端做成了运营(打杂)。 这是一个在线问诊的医疗项目,这个项目和人家有很大的合作机会,因为合作的公司在线的用户很多(其实真实到底有多少也不清楚,只是ppt上写的很多,经过我对他们app的分析是和他们提供的数据有差距的),但是没有办法进入私域,而我们有一套私域系统,但是没有用户进来,但是我们要做的工作,还是主要是运营方案的设计,因为要有一套完整的运营方案出来,然后才能将用户引入到私域中,然后我们的系统才可以对接。 然后我们就不停的开会,讨论,做竞品分析,知道现在还在做一些流程分析: 用户如何加入?加入后怎么转化?发什么样的欢迎语?推荐的产品是什么? … 这些问题都是需要解决的问题,落地这件事情真的很难,因为每个人的奇思妙想,都会导致项目落地困难,而且说到底我们不是一个真正的运营师,我们没有运营成功项目的经验,我们大部分的思考都是基于用户和开发者的心态去思考,所以很有可能会在设计方案的根上就出现了问题,所以到时项目推进缓慢,目前还好的是这个项目正在积极的推进,不过谁也不知道结果。 总结 &emsp今年一年,从一个前端开发慢慢的做了一些运营的工作,其实在接触到的那一刻是很反感的,因为要写文档,要沟通,而且天马行空的想法层出不穷,无休无止的会,但是没办法,今年互联网不景气,那只能接受一下自己不想接受的事情,谁让自己是个打工人呢,不过经历过回想起来其实也感觉最起码对很多东西有了一个简单的认知,可能以后得某一天会用的上,作为一个学历不是很高的人,在开发的行业上能走多远真的不清楚,所以有机会接受一些新的知识,我内心其实是不抵触的,毕竟也得为自己以后打算一下,万一以后用上这点特殊的工作经历呢,那技术方面肯定也不能拉下,没事的时候就多看看,多写写代码。 只是作为一个员工,心里是很不爽的,就会想为什么要把别人的工作交给自己呢?其实我也不知道公司是怎么想的,反正就是一直在招相关的人,但是招了一年也没招到,只好让我们这些开发人员顶上,不过这也不是我该关心的事情,毕竟公司不是我的,负责好自己的事情就可以了,在自己力所能及的范围内接受。 此篇对今年的工作做个简单的记录,整体分析,代码写了不少,一个没用上,学到了一些奇奇怪怪的知识。 新的一年马上到了,希望可以心想事成,平安顺遂,还能赚个小钱~

面试中遇到的设计题

1. 如何设计秒杀系统 前端: a. 一些防刷单校验,拉长整个交易流程,起到一个削峰作用 b. 静态资源多CDN部署 c. 前端缓存,有些页面的切换,不需要调用后端接口 后端: 接口性能优化:使用缓存,异步,多线程,功能降级等手段 还有些高并发时保证系统稳定性的手段:扩容, 升配,限流,降级 还有是想做系统隔离/数据隔离的方案 这种成本很高。 2. 红包系统怎么设计 1. 模型设计 红包池表,红包账户表,红包池表 2. 怎么支持高并发? 高并发需要考虑这个并发是有多高?拿redis可支撑的写入速度作为分界线,8万/秒。 如果并发低于这个值?这个场景较好处理,使用redis作为主要的存储介质,需要使用lua脚本完成红包金额生成,红包扣减等动作。 如果高于这个值?可以考虑下吗几种方案? 一是. 使用消息队列,异步的方式,处理抢红包的请求,起到一个削峰的作用。配合的玩法,用户抢到红包后,需要一定的时间后才能打开红包。 二是. 将一个大红包均分成多个副本,每个副本分布在不同的redis节点上。再有一个前置的负载均衡器,可以将请求均匀的打在不同的节点上。解决单点瓶颈。 最后,为了保证系统的稳定,一定要做限流。预期外的流量,不要接受。 3. 怎么做一个唯一id的生成器 雪花算法 41位的时间戳 + 10位机器码 + 12位序列号 时间戳是毫秒级;机器码由用户指定可能有重复的风险;12位序列号的范围是0~4096; 4. 分布式限流怎么做 使用令牌桶。原理:算法以固定的速度向桶中存放令牌;桶有一定的容量,如果桶满了,则将新生成的令牌丢弃;有请求过来会消耗令牌。 主要有4种算法: 固定窗口:边界值,无法精确限流,不可控。 滑动窗口:更为精确,但是没办法处理短时的高峰流量。 漏桶:处理请求的速度是恒定的,没有办法快速处理短暂的高峰流量 令牌:可以处理短暂的高峰流量,并且后面可以做到匀速的处理请求 面试必备:4种经典限流算法讲解 - 文章详情 如何选择QPS限流算法和令牌桶算法_金融分布式架构-阿里云帮助中心 5. 100万考生,高考排名怎么做? 思路1:计数排序 假设最高分是700 700,699,698.。。500。。。。4,3,2,1,0 每个分数一个bucket,然后存储分数对应的学生数量 6. 10亿数组去重排序 思路1:如知数组中的范围,可以按数值范围分成多个组,比如1-10000,10001-20000等。遍历原数组将每个数投递到对应范围的数组中。当然最极致的做法就是每个组一个元素,这样不需要排序就是有序的了。 如果不知道范围: 借助hash算法思想,把一个大文件哈希分割到多个小文件中,而哈希冲突的数字 一定会在同一个小文件中,从而保证了子问题的独立性,小文件可以使用set结构去重,然后就可以单独对小文件通过快速排序来排序。最后再通过多指针的方式进行全局范围的排序 7. 游戏top实时排行榜 思路1:小顶堆 8. 设计微信摇一摇功能(设计微信附近的人功能) 假设自己的位置的经纬度是j,w, i 表示范围。那么附近的人的原理就是检索范围在j-i<经度<j+i, w - i<维度< w + i;

ubuntu下vscode报错 System limit for number of file watchers reached

1 解释 “System limit for number of file watchers reached”意思是“达到文件观察者数量的系统限制”。错误产生的原因是负责监控 Linux 文件系统的 inotify 程序达到了系统默认的限制上限。 查看 Inotify 在内核中的默认配置。 sysctl fs.inotify 输出 fs.inotify.max_queued_events = 16384 # inotify 管理的队列的最大长度 fs.inotify.max_user_instances = 128 # 每个用户所能创建的 Inotify 实例的上限 fs.inotify.max_user_watches = 65536 # 每个 Inotify 实例最多能关联几个监控 (watch) 2 解决办法 增加 inotify watchers 的上限数量 3 步骤 运行命令sudo nano /etc/sysctl.conf在最后面加入fs.inotify.max_user_watches=524288保存后退出运行命令sudo sysctl -p

ASF-YOLO开源 | SSFF融合+TPE编码+CPAM注意力,精度提升!

目录 摘要 1 Introduction 2 Related work 2.1 Cell instance segmentation 2.2 Improved YOLO for instance segmentation 3 The proposed ASF-YOLO model 3.1 Overall architecture 3.2 Scale sequence feature fusion module 3.3 Triple feature encoding module 3.4 Channel and position attention mechanism 3.5 Anchor box optimization 4 Experiments 4.1 Datasets 4.2 Implementation details 4.3 Quantitative results 4.4 Qualitative results 4.5 Ablation study 4.5.1 Effect of the proposed methods 4.5.2 Effect of attention mechanisms

面向对象基础

面向对象概述 面向对象和面向过程的区别 面向过程: 优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发,能是最重要的因素。 缺点:没有面向对象易维护、易复用、易扩展 面向对象: 优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护 缺点:性能比面向过程低 面向过程是具体化的,流程化的,解决一个问题,你需要一步一步的分析,一步一步的实现。 面向对象是模型化的,你只需抽象出一个类,这是一个封闭的盒子,在这里你拥有数据也拥有解决问题的方法。需要什么功能直接使用就可以了,不必去一步一步的实现,至于这个功能是如何实现的,管我们什么事?我们会用就可以了。 面向对象的底层其实还是面向过程,把面向过程抽象成类,然后封装,方便我们使用的就是面向对象了。 面向对象三大特性 面向对象的特征主要有以下几个方面: 封装 封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如 果属性不想被外界访问,我们大可不必提供方法给外界访问。但是如果一个类没有提供给外界访问的方法,那么这个类也没有什么意义了。 继承 继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新 的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用 继承我们能够非常方便地复用以前的代码。 关于继承如下 3 点请记住: 1.子类拥有父类非 private 的属性和方法(包括私有属性和私有方法),但是父类中的私有属性和方法子类是无法访问的,只是拥有。 2.子类可以拥有自己属性和方法,即子类可以对父类进行扩展。 3.子类可以用自己的方式实现父类的方法。 多态 多态,顾名思义,表示一个对象具有多种的状态,具体表现为父类或接口定义的引用变量可以指向子类或具体实现类的实例对象,提高了程序的拓展性。 多态的特点: 对象类型和引用类型之间具有继承(类)/实现(接口)的关系;引用类型变量发出的方法调用的到底是哪个类中的方法,必须在程序运行期间才能确定;多态不能调用“只在子类存在但在父类不存在”的方法;如果子类重写了父类的方法,真正执行的是子类覆盖的方法,如果子类没有覆盖父类的方法,执行的是父类的方法。抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行 为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是 什么。 什么是多态机制?Java语言是如何实现多态的? 所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出 的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。 多态分为编译时多态和运行时多态。 在Java中有两种形式可以实现多态:继承(多个子类对同一方法的重写)和接口 (实现接口并覆盖接口中同一方法)。 方法重载(overload)实现的是编译时的多态性(也称为前绑定),而方法重写(override)实现的是运行时的多态性(也称为后绑定)。 Java实现多态有三个必要条件:继承、重写、向上转型。 继承:在多态中必须存在有继承关系的子类和父类。 重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的 方法。 向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具 备技能调用父类的方法和子类的方法。 只有满足了上述三个条件,我们才能够在同一个继承结构中使用统一的逻辑实现代码处理不同的对象,从而达到执行不同的行为。 对于Java而言,它多态的实现机制遵循一个原则:当超类对象引用变量引用子类 对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但 是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。 面向对象五大基本原则是什么 单一职责原则SRP(Single Responsibility Principle):类的功能要单一,不能包罗万象,跟杂货铺似的。开放封闭原则OCP(Open-Close Principle):一个模块对于拓展是开放的,对于修改是封闭的里式替换原则LSP(the Liskov Substitution Principle LSP):子类可以替换父类出现在父类能够出现的任何地方。依赖倒置原则DIP(the Dependency Inversion Principle DIP):高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。抽象不应该依赖于具体实现,具体实现应该依赖于抽象。接口分离原则ISP(the Interface Segregation Principle ISP):设计时采用多个与特定客户类有关的接口比采用一个通用的接口要好。 Java的四种引用,强弱软虚 强引用 Java中默认声明的就是强引用,强引用是平常中使用最多的引用,强引用在程序内存不足(OOM)的时候也不会被回收,使用方式:

Java数据类型相关

数据类型 Java有哪些数据类型 定义:Java语言是强类型语言,对于每一种数据都定义了明确的具体的数据类 型,在内存中分配了不同大小的内存空间。 分类: 基本数据类型 数值型 整数类型(byte,short,int,long) 浮点类型(float,double) 字符型(char)布尔型(boolean) 引用数据类型 类(class)接口(interface)数组([]) Java基本数据类型图 Java中各种数据默认值 Byte,short,int,long默认是都是0 Boolean默认值是false Char类型的默认值是’’ Float与double类型的默认是0.0 对象类型的默认值是null 超过 long 整型的数据应该如何表示? 基本数值类型都有一个表达范围,如果超过这个范围就会有数值溢出的风险。 在 Java 中,64 位 long 整型是最大的整数类型。 long l = Long.MAX_VALUE; System.out.println(l + 1); // -9223372036854775808 System.out.println(l + 1 == Long.MIN_VALUE); // true BigInteger 内部使用 int[] 数组来存储任意大小的整形数据。 相对于常规整数类型的运算来说, BigInteger 运算的效率会相对较低。 String 属于基础的数据类型吗? String 不属于基础类型,基础类型有 8 种:byte、boolean、char、short、int、float、long、double,除了基本类型(primitive type)和枚举类型(enumeration type),剩下的都是引用类型(reference type)。 用最有效率的方法计算 2 乘以 8 2 << 3(左移 3 位相当于乘以 2 的 3 次方,右移 3 位相当于除以 2 的 3 次 方)。

联合查询为什么小表要放在前面

在Mysql的查询优化里有一条经验,在联合查询时,SQL里要把小表放在大表的前面。小表是指数据量少的表。这个经验的原理是什么呢?这就要从Mysql的遍历方式开始说起。 遍历方式 Mysql的联合查询是按照嵌套查询的方式进行遍历。先从第一个表取出一条数据,在第二个表里搜索符合条件的数据。再从第二个表里取出一条数据,在第三个表里搜索符合条件的数据。一直递归到最后一个表,如过有符合条件的数据就放到结果集里。最后一张表没有符合条件的数据后,就再回到倒数第二张表,找到符合条件的下一条数据。直到第一张表的数据都遍历完为止。 这种遍历方式的成本是多少,我们可以简单估算一下。 遍历的成本 嵌套遍历的成本,即查找的次数公式是 (cost1cnt0) + (cost2cnt1) + … + (costN*cntN-1)。cost代表找到一条满足条件数据需要扫描的行数,cnt是需要找的行数,cnt0是常数1。 没走的索引的情况 没有用到索引的情况,就要全表扫描,所以cost就是表的行数。公式里表的行数我们是没发控制,能控制的是调整表的顺序,产生不同的cnt。这里就有几个规则: 第一个表需要全部扫描,把数据行少的表放前面也许更划算将数据行多的表放后面,countN * cntN-1公式里的cntN-1的值更小的概率越大,即减少大表的总遍历次数 但是,在没有实际执行之前,是不知道每个cnt的值。所以,什么样的表顺序更优其实是不确定。例如,table1、table2分别有有100、1000条数据。从table1开始遍历如果有50条数据满足条件,那么成本就是100 + 50 * 1000 = 50100。从table2开始遍历如果有10条数据满足条件,那么成本就是1000 + 10 * 100 = 2000。这样看,table2放前面更好。 走索引的情况 走索引的情况联合查询的方式会有一些区别。先从第一个表取出一条数据,在第二个表的索引里搜索符合条件的数据。用索引搜索的时间复杂度是O(logn),count值就从数据行数变成了log(count),公式还是一样。 所以,按照经验是将小表放到前面会好一些,但也不是绝对的。大部分情况下查询优化器会帮我们去选择表的顺序,所以我们没必要刻意的去调整表的顺序。通过explain命令可以看到优化后的执行顺序。 explain select * from table1, table2 where table1.oid = table2.oid; +--+-----------+---------+----------+----+-------------+-------------+-------+-------+----+--------+-----+ |id|select_type|table |partitions|type|possible_keys|key |key_len|ref |rows|filtered|Extra| +--+-----------+---------+----------+----+-------------+-------------+-------+-------+----+--------+-----+ |1 |SIMPLE |table1 |null |ALL |null |null |null |null |31 |100 |null | |1 |SIMPLE |table2 |null |ALL |null |null |null |null |203 |100 |null | +--+-----------+---------+----------+----+-------------+-------------+-------+-------+----+--------+-----+ 如果优化器选错了顺序,我们可以通过straight_join关键字去忽略优化器的顺序优化。

vue引用public文件夹中文件

1 官方解释 vite官网解释 2 使用 可以先看最下面结论 在Test.vue组件中测试 2.1 图片文件 方式一(ide正常,页面正常,img标签src属性赋值绝对路径/): <template> <div class="view"><img src="/moon.png" /></div> </template> <script setup lang="ts"> console.log("aaa"); </script> <style scoped> img { width: 300px; height: 300px; } </style> build后: 页面显示: 方式二 (ide警告,页面正常,img标签src属性赋值绝对路径/public) <template> <div class="view"><img src="/public/moon.png" /></div> </template> <script setup lang="ts"> console.log("aaa"); </script> <style scoped> img { width: 300px; height: 300px; } </style> ide警告: build后: 可以看到,这样的方式引用,会把图片文件复制一份,名称追加hash值,放在assets下面,根目录下的moon.png并没有被引用 页面显示: 方式三(ide警告,页面正常,img标签src属性赋值相对路径../../public): <template> <div class="view"><img src="../../public/moon.png" /></div> </template> <script setup lang="

win10重装系统历程

win10系统更新出问题了,重置系统卡死,遂决定重装。 微软官方工具制作U盘启动盘, 进行到分区时,一冲动把盘都格式化了, 后面了解到,即便进不了系统也有办法备份数据的... 进行到安装时,提示Windows无法安装所需的文件,请确保安装所需的所有文件可用,并重新启动安装,错误代码:0x8007025D. 以为是没制作好,于是重新制作一遍U盘启动盘,当时用的别的台式机, 看网上说专门把U盘插到机箱后面的接口上了,但进行到这一步还是出现这个问题, 网上搜到相关问题,看到有大佬分享用WinPE加镜像ISO重装成功的, 于是去B站看了教程,U盘装了WinPE也放上系统镜像了, 这回系统镜像是从MSDN,I tell you 上下载的, 现在更新了,登录 (itellyou.cn) 进行到安装时还是这个Windows无法安装所需的文件... 只是错误代码变了:0x80070571, 看网上说也有可能是U盘的问题,我用的闪迪的U盘, 从BIOS里看到硬盘是金士顿,又买了个金士顿的U盘, 注册了Itellyou,也捐赠了,下载系统时看到作者分享的制作U盘启动盘的工具, 比如Ventoy,但是没有推荐PE,于是去B站看Ventoy的教程, 买的U盘到了,就装了Ventoy,感觉就像没装一样,U盘里看不到, 然后把ISO文件放U盘里 再重装,刚开始蓝屏提示Verification failed 0x1A... 网上一搜搜到了, Ventoy官网也有,Secure Boot (安全启动) 按之操作,可以了,最后安装也顺利进行

RHEL7.5编译openssl1.1.1w源码包到rpm包

openssl1.1.1w下载地址 https://www.openssl.org/source/ 安装依赖包 yum -y install curl which make gcc perl perl-WWW-Curl rpm-build wget http://mirrors.aliyun.com/centos-vault/7.5.1804/os/x86_64/Packages/perl-WWW-Curl-4.15-13.el7.x86_64.rpm rpm -ivh perl-WWW-Curl-4.15-13.el7.x86_64.rpm 创建编译时需要的目录 mkdir -p /root/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS} 上传源码包到指定目录 cp openssl-1.1.1w.tar.gz /root/rpmbuild/SOURCES/ 新建编译文件 cat << 'EOF' > /root/rpmbuild/SPECS/openssl.spec Summary: OpenSSL 1.1.1w for redhat Name: openssl Version: %{?version}%{!?version:1.1.1w} Release: 1%{?dist} Obsoletes: %{name} <= %{version} Provides: %{name} = %{version} URL: https://www.openssl.org/ License: GPLv2+ Source: https://www.openssl.org/source/%{name}-%{version}.tar.gz BuildRequires: make gcc perl perl-WWW-Curl BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root %global openssldir /usr/local/openssl1.1.1w %description OpenSSL RPM for version 1.

京微齐力:基于H7的平衡控制系统(一、姿态解析)

目录 前言一、关于平衡控制系统二、实验效果三、硬件选择1、H7P20N0L176-M2H12、MPU6050 四、理论简述五、程序设计1、Cordic算法2、MPU6050采集数据3、fir&iir滤波4、姿态解算 六、资源消耗&工程获取七、总结 前言 很久之前,就想用纯FPGA做一套控制系统。可以用到平衡车、飞控、水陆两栖船上面,让很多想快速入门比赛的学子,能够在这套“底盘”上面,结合图像处理、多信息融合等技术,快速搭建出自己的作品。恰逢认识FPGA之旅的作者-吴工,他也在做这件事,顿感追攀更觉相逢晚,恨不相逢早。对未来的真正慷慨,是把一切都献给现在,不再想,今天就开始做! 一、关于平衡控制系统 我们惊叹舞蹈演员在舞台上飞快地旋转,而身体却不会倾倒;我们佩服体操运动员一连翻几个筋斗,却能稳稳落地。如果我们不注意被石头绊着时,我们会“下意识”地立刻纠正身体的姿势,不让自己轻易摔倒。我们体内有一套维持身体平衡的器官系统在默默地为我们工作着。 人既是如此,那么机器也是这样的,机器要保持机身平衡,也需要这样一个器官系统来修正机器的运动。这种器官有很多,姿态传感器就是其中一种。目前主流的姿态传感器有三轴、六轴及九轴三种。这九轴分别就是:三轴加速度计,三轴陀螺仪以经三轴磁场。 作为本系列文章的开篇,本次实验,先选用较为中等的六轴-MPU6050作为姿态传感器,后面会慢慢根据系统来升级传感器。MPU6050由三轴加速度计和三轴陀螺仪组成,它可以测量物体在x、y、z三个方向上的加速度和角速度。加速度计可以检测物体的线性加速度,而陀螺仪可以检测物体的角速度。通过将加速度计和陀螺仪的测量结果进行组合,可以计算出物体的方向和角度。 关于六轴传感器的坐标系分析,网上很多,本文就不做赘续,有兴趣的可以自己查一查。 二、实验效果 1、FPGA采集MPU6050的数据,并进行滤波; 2、FPGA以串口的方式,将姿态数据发送到上位机。 基于H7的控制平衡系统(一) 从视频可以看到,当MPU6050姿态发生变化时,上位机波形跟传感器变化一致。yaw需要做角速度求解,这里只做了相对开始位置的,即初始值,所以只有在开始可以看到一点,后面的波形看不到。(具体原因请看第四节:理论简述) 三、硬件选择 1、H7P20N0L176-M2H1 本次实验使用H7作为主控板,HME-H7系列采用低功耗22nm 技术,集成了高性能ARM Cortex-M3 MCU(频率高达300M)、外围设备与大容量片上SRAM。本次实验只使用逻辑部分,后面根据需要再扩展MCU实验。需要板子的同学,可以到米联客店铺购买。 2、MPU6050 MPU6050采用I2C总线通信协议,可以直接连接到微控制器或单片机上。在使用MPU6050之前,需要进行校准,以保证其测量结果的准确性。校准过程可以通过软件或硬件进行。将VCC、GND、SCL、SDA连接到H7开发板即可。 MPU6050框图 四、理论简述 物体的姿态,通俗的讲,就是通过六轴数据求解三个角度: roll:绕X轴(横滚) 范围:±180° ,与旋转方向相反转是增大 – 右滚为正,左滚为负; pitch:绕Y轴(俯仰)范围:±90°,与旋转方向相反转是增大-- 抬头为正,低头为负; yaw:绕z轴(偏航) 范围:±180° ,与旋转方向相反转是增大 --右偏为正,左偏为负。 当我们得到MPU6050的原始数据时,接下来如果我们要真正用上这些数据,通常我们都会利用数学方法把它们转换成角度。 1、加速度求解角度的表达式 注:通过加速度是无法求解yaw的,因为重力加速度的Z轴,在相对地平面东西南北旋转时并无变化,因此只能靠Z轴的角速度来惯性累计估算旋转角度。 roll = atan(acc_y / acc_x); pitch = atan(acc_x / (sqrt(acc_y*acc_y + acc_z * acc_z))); 2、通过角速度求解: 通过角速度的求解就更简单了,只需要将当前角度加上(角速度×dt)就可以。角速度求解的时候会有些问题,在静态的时候,角速度会有零漂,这个时候角度误差会越来越大。 可以看到有上面的两种方法求解角度,可以单独使用,但是可能会不太准确,精度要求不高的场合可以只使用加速度求解。在精度要求比较高的场合下,需要使用这两种方法求解,然后再将求得的结果进行融合。常用的方法有: 卡尔曼滤波、清华角度滤波、一阶互补滤波、四元数解算。 这几种方法中,从难度上来看,一阶互补滤波和清华角度滤波是比较容易理解的,而且它们的本质其实是相同的,都是利用了权重互补,它们调试起来比较简单,而卡尔曼滤波和四元数解算的方法比较难理解。当然利用DMP直接输出角度也是可以的,不过移植起来也不太容易。从滤波效果上来看,本人的理解是:DMP直接输出角度>卡尔曼滤波>=四元数解算>清华角度滤波>=一阶互补滤波。 不过其实一阶互补滤波只要把调试得比较好,得到的角度还是够用的。 一阶互补滤波: roll = a * acc_roll + (1 - a) *gyro_roll; 五、程序设计 1、Cordic算法 求解:

PythonStudio:一款国人写的python及窗口开发编辑IDE,可以替代pyqt designer等设计器了

本款软件只有十几兆,功能算是强大的,国人写的,很不错的python界面IDE.顶部有下载链接。下面有网盘下载链接,或者从官网直接下载。 目前产品免费,以后估计会有收费版本。主页链接:PythonStudio-硅量实验室 作者还贴心的制作了视频教程,真贴心啊。 赠送官方视频教程 视频链接:https://pan.baidu.com/s/18uBqslsPXkNmsv54d72uTQ 提取码:1111 IDE链接:https://pan.baidu.com/s/1PF9tYsU4cYHwfpeTBI0Q4Q 提取码:1111 使用本款IDE生成的exe文件,大小为十几兆,使用的是delphivcl包,使用pyinstaller来打包。PythonStudio会自动下载缺失的依赖包。这一点太友好的,特别是对小白。 设计窗体的时候,可以双击按钮,它会自动生成按钮点击事件,然后填写相关的代码,类似vs窗体设计IDE的形式,比pyside等窗口代码分离友好多了。 不管怎么说,这个作者可谓诚意满满的。

Java中的强引用、软引用、弱引用、虚引用与引用队列 通俗举例实战详解

文章目录 1. 基本概念2. 代码演示2.1 软引用代码演示2.2 弱引用代码演示2.3 弱引用+引用队列代码演示2.4 虚引用代码演示2.5 虚引用+引用队列代码演示 3. 实战样例3.1 利用软引用实现资源对象缓存3.2 利用弱引用实现临时行为数据缓存3.3 利用虚引用+引用队列实现资源释放 本次实验Java版本:JDK 1.8.0_152_release 1. 基本概念 本节先了解一下概念,看不懂没关系,后续会详解。 Java中的引用可以按强弱程度分为四种,JVM对不同程度的引用回收策略不同: 强引用(Strong Reference):我们平时用的都是强引用。例如:MyObject myObj = new MyObject(); 回收:只要有引用,就不会被回收。 软引用(Soft Reference):使用SoftReference显式声明。 回收:当JVM内存不够时,会对软引用对象进行回收。应用场景:做资源类缓存。使用样例: MyObject myObject = new MyObject("Amy"); // 从数据库中获取数据 SoftReference<MyObject> reference = new SoftReference<>(myObject); // 增添软引用 // do something ... myObject = reference.get(); // 尝试获取myObject对象 if (myObject == null) { // 没获取到,说明已经被JVM回收了 myObject = new MyObject("Amy"); // 重新从数据库中获取数据 } else { // 没有被JVM回收 } 弱引用(Weak Reference):使用WeakReference显式声明。

如何实现 Es 全文检索、高亮文本略缩处理(封装工具接口极致解耦)

如何实现 Es 全文检索、高亮文本略缩处理 前言技术选型JAVA 常用语法说明全文检索开发高亮开发Es Map 转对象使用核心代码 Trans 接口(支持父类属性的复杂映射)Trans 接口可优化的点高亮全局配置类如下真实项目落地效果为什么不用 numOfFragments、fragmentSize 参数控制略缩? 前言 最近手上在做 Es 全文检索的需求,类似于百度那种,根据关键字检索出对应的文章,然后高亮显示,特此记录一下,其实主要就是处理 Es 数据那块复杂,涉及到高亮文本替换以及高亮字段截取,还有要考虑到代码的复用性,是否可以将转换代码抽离出来,提供给不同结构的索引来使用。 技术选型 像市面上有的 Spring Data,码云上面的 GVP 项目 (EasyEs)等其他封装框架。使用起来确实很方便,但是考虑到由于开源项目的不稳定性且 Es 不同版本间语法差异比较大,还有一方面是公司之前用的一直是 Es 6,后续可能会涉及到 Es 的升级改造,于是决定使用原生的 Api。也就是使用 RestHighLevelClient。 JAVA 常用语法说明 查时间范围内的数据 BoolQuery 里面嵌套一个 RangeQuery 即可在RangeQuery 里面指定时间范围。BoolQuery.must() 各位理解为 Mybatis 中的 eq 方法即可,必须包含的意思。 RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery(articleRequest.getSortType()); if (StringUtils.isNotEmpty(articleRequest.getBeginTime())) { rangeQuery.gte(articleRequest.getBeginTime()); } if (StringUtils.isNotEmpty(articleRequest.getEndTime())) { rangeQuery.lte(articleRequest.getEndTime()); } boolQuery.must(rangeQuery); BoolQuery.should() 方法可以理解为 OR 可包含可不包含,多字段全文检索时应用 shoud。 BoolQueryBuilder boolQuery = QueryBuilders.

jmeter使用入门(+influxdb+grafana)

目录 一、jmeter实际模拟一个http请求 1、背景 2、具体步骤 二、jmeter发送wss(websocket)请求 三、jmeter的可视化—— +influxdb+grafana 0、准备 1、安装influxdb 2、jmeter通过Backend Listener连接influxdb 2、安装grafana 3、查看执行效果 四、jmeter安装常用插件 1、安装插件管理器 2、配置udp请求 五、Linux下的非GUI模式压测 六、Jmeter分布式压测 七、常用工具收藏 官网: Apache JMeter - Download Apache JMeter 一、jmeter实际模拟一个http请求 以后就可以用jmeter来压测接口了,而且是从前端http接口层面的压测。 1、背景 背景很简单就是想用jmeter模拟一个实际业务中用到的http请求,对应功能点如下。 其对应的接口,请求时候所带的cookie、参数、payload等都可以通过开发者工具中看到。 注:网上请求百度的case很多了,没什么可说的。我们贴合实际业务场景,直接去请求saas软件的一个实际业务接口。这种情况需要考虑登录态(cookie)等问题也更贴合实际,为此有必要专门演示一把。 2、具体步骤 打开浏览器调试工具,打开jmeter。 (1)利用jmeter的 import from cURL进行导入。 ①调试工具中选中目标接口→右键→copy→copy as cURL 注:其copy下来的其实是如下一串结果。按理来说应该是包括所有的必要信息了才是。 curl 'https://testgateway.qidian.qq.com/v1/interface/inner/cloudcc_303213' \ -H 'authority: testgateway.qidian.qq.com' \ -H 'accept: application/json, text/plain, */*' \ -H 'accept-language: zh-CN,zh;q=0.9' \ -H 'content-type: application/json' \ -H 'cookie: login_url=https%3A%2F%2Foaconsole.qidian.qq.com%2Flogin%2F%3Fshow_type%3Dqa%26source%3Dworkbench; d2=Tcxl6Jtcmi8MwUIZvsayrx7yxmoeO0z6CGTBYhD59zvH1JjuFqQBzAzSLoG50Z0W93RXa1giPvYP14sswnxOMGCYLgR0SygSguzlcjr14zu8pEnRkRQ3D3Cna19tOi0ooGy0RZeBvn3mrBjaKGFewVadcAnb2xu6lx18ZBN8Z4YM0l8XeBecL+E1W2NOnNQud44gYmp6nLzJg/nQbq0WGoAZ31YcIF4zkS3XFQ+Ip3OhDsTSJvT78g==; corp_uin=2852199388; aid=3007442117; aid_skey=belsR+0zPsl3noSHqgbQUEcY2xngQtQ+yrunvtMpyDtEhJnCOJ3oVymCaaWPnUvZsJpG42neuoazR48ylhQFwPrerrlH2OoL19oEADpcGL6xGGVXQj1XUvnjlNyjWbovPHqfPXzY+De61sTHYYJTvdl3jVoo2FmIkUc6zriSQ3Q=; login_type=workbench; source=workbench; logout_type=workbench; qd_admin_is_web=yes; qd_aid_encode=bfbf632e80afd3bb63602fe46a812976; qdui_loginaccount=fy@2852199388.

【无标题】python和Pytorch中的矩阵乘法运算总结

在数据科学中,矩阵乘法用得特别频繁,而python中有多种矩阵乘法,现作一个简单总结。 1、python中numpy库的矩阵乘法 (1)矩阵乘法 第一种: np.matmul() import numpy as np x=np.array([[1, 2, 3], [4, 5, 6]]) y=np.array([[1, 2], [3, 4], [5, 6]]) np.matmul(x,y) 第二种:@运算 x = np.array([[1, 2, 3], [4, 5, 6]]) y = np.array([[1, 2], [3, 4], [5, 6]]) x@y 第三种:np.dot(A, B)矩阵乘法,点乘 x = np.array([[1, 2, 3], [4, 5, 6]]) y = np.array([[1, 2], [3, 4], [5, 6]]) np.dot(x,y) 上述三个函数均可执行向量的内积运算,如 x = np.array([1,2,3]) y = np.array([4,5,6]) np.dot(x,y)#32 x@y#32 np.matmul(x,y)#32 可以看出,这三种乘法都是一样的,但是一般情况,官方推荐,矩阵乘法使用前两种,内积运算使用第三种。

安装NETDATA集群监控面板

安装NETDATA集群监控面板 介绍 官方链接 演示网页:https://my-netdata.io/ 官方首页:http://netdata.cloud/ 文档地址:http://docs.netdata.cloud github地址:https://github.com/netdata/netdata#infographic 安装 官网提供一键安装脚本 bash <(curl -Ss https://my-netdata.io/kickstart.sh) 国内使用一键安装脚本需要添加参数 bash <(curl -Ss https://my-netdata.io/kickstart.sh) --stable-channel 修改主节点的配置 # 主服务器配置 # 生成uuid格式的字符串 root@cby:~# uuidgen 856a8565-75ac-441f-89e1-2d983272cfde root@cby:~# vim /etc/netdata/stream.conf root@cby:~# cat /etc/netdata/stream.conf [856a8565-75ac-441f-89e1-2d983272cfde] enabled = yes default history = 3600 default memory mode = save health enabled by default = auto allow from = * root@cby:~# root@cby:~# # allow from 可以设置数据流的允许来源以保证安全 # destination 是主节点ip地址 # 重启netdata root@cby:~# systemctl restart netdata root@cby:~# 配置其他节点 # 其它服务器配置 root@cby:~# vim /etc/netdata/netdata.

Spring Boot 配置外部化中文文档

本文为官方文档直译版本。原文链接 Spring Boot 配置外部化中文文档 前言访问命令行属性JSON 应用程序属性外部应用程序属性可选位置通配符位置特定配置文件导入附加数据导入无扩展名的文件使用配置树属性占位符使用多文档文件 激活属性加密属性使用 YAML映射 YAML 到属性直接加载 YAML 配置随机值设置系统环境属性类型安全的配置属性JavaBean 属性绑定构造函数绑定启用 @ConfigurationProperties使用 @ConfigurationProperties第三方配置宽松绑定绑定Map从环境变量绑定缓存 合并复杂类型属性转换转换Duration转换Period转换DataSize @ConfigurationProperties 验证@ConfigurationProperties 对比 @Value 前言 Spring Boot 允许您将配置外部化,这样您就可以在不同的环境中使用相同的应用程序代码。您可以使用各种外部配置源,包括 Java 属性文件、YAML 文件、环境变量和命令行参数。 属性值可以通过 @Value 注解直接注入到 Bean 中,也可以通过 Spring 的Environment抽象访问,还可以通过 @ConfigurationProperties 绑定到结构化对象中。 Spring Boot 使用一种非常特殊的 PropertySource 顺序,旨在允许对值进行合理的覆盖。后面的属性源可以覆盖前面属性源中定义的值。属性源按以下顺序考虑: 默认属性(通过设置 SpringApplication.setDefaultProperties 指定)。配置类上的 @PropertySource 注解。请注意,在应用程序上下文刷新之前,此类属性源不会添加到环境中。这对于配置某些属性(如 logging.* 和 spring.main.*)来说为时已晚,因为这些属性是在刷新开始前读取的。配置数据(如 application.properties 文件)。RandomValuePropertySource 只包含 random.* 中的属性。操作系统环境变量。Java 系统属性(System.getProperties())。来自 java:comp/env.NET 的 JNDI 属性。ServletContext 初始参数。ServletConfig 初始参数。SPRING_APPLICATION_JSON 中的属性(嵌入到环境变量或系统属性中的内联 JSON)。命令行参数。测试属性 在 @SpringBootTest 和测试注解中可用,用于测试应用程序的特定片段。在测试中使用 @DynamicPropertySource 注解。测试中的 @TestPropertySource 注解。Devtools 激活时,$HOME/.

VUE篇之日历组件

1.简单日历组件展示 思路:根据当前月的第一天是星期几,来显示日期 <template> <div class="wrap"> <el-button @click="preMonth">上个月</el-button> <el-tag>当前年份{{ curYear }}</el-tag> <el-tag>当前月份{{ curMonth }}</el-tag> <el-button @click="nextMonth">下个月</el-button> <div class="weeks"> <div v-for="item in week" :key="item" class="week">{{ item }}</div> </div> <div class="days"> <!-- 当月 --> <div v-for="item in curDays" :key="item + 'cur'" class="curday">{{ item }}</div> </div> </div> </template> <script> import moment from 'moment'; moment.suppressDeprecationWarnings = true; export default { data() { return { curYear: moment().year(), //当前年 curMonth: moment().month() + 1, //当前月 week: ['一', '二', '三', '四', '五', '六', '七'], firstDay: moment(`${moment().

Node.js创建一个简单的WebSocket接口,实现通信交互

Node.js创建一个简单的WebSocket接口,实现通信交互 一、为什么使用WebSocket? WebSocket,最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。 WebSocket 是一种在 TCP 连接上进行全双工通信的 API 技术。相比于传统的 HTTP 类型 API,WebSocket 类型接口有着更低的延迟和更高的效率,它适用于需要长时间保持连接并实时传输数据的场景,例如在线游戏、实时聊天等服务。 WebSocket是一种基于HTTP的长链接技术。传统的HTTP协议是一种请求-响应模型,如果浏览器不发送请求,那么服务器无法主动给浏览器推送数据。如果需要定期给浏览器推送数据,例如股票行情,或者不定期给浏览器推送数据,例如在线聊天,基于HTTP协议实现这类需求,只能依靠浏览器的JavaScript定时轮询,效率很低且实时性不高。 WebSocket特点: 在实现数据推送时,多数都是ajax轮询(在特定的时间间隔,由浏览器主动发起请求,会占用很多带宽和服务器资源)。而WebSocket建立TCP连接后,服务器可以主动给客户端传递数据,能够更好的节省服务器资源和带宽,实现更实时的数据通讯。 因为WebSockets只能通过连接发送纯文本数据和二进制数据,所以对于复杂的数据结构,在通过连接发送之前,必须进行JSON.stringify()序列化。 协议标识符是ws(加密则为wss),服务器网址就是 URL。如“ws://localhost:8080"。 二、示例代码 简单的WebSocket接口 ws 是一个简单易用、速度极快且经过全面测试的 WebSocket 客户端和服务器实现。 npm install ws const http = require("http"); const WebSocket = require("ws"); const server = http.createServer(); // const WebSocketServer = WebSocket.WebSocketServer; const socket = new WebSocket.Server({ server }); socket.on("connection", (scoket) => { console.log("连接已打开"); scoket.on("message", (msg) => { console.log("收到消息==》" + msg); scoket.send("返回==》" + msg); }); scoket.on("close", (msg) => { console.

Matlab图像处理——RGB分量提取、变换、组合

1、问题提出 读取RGB彩色图像,将红色分量,绿色分量。蓝色分量提取出来,分别进行如下变化:像素值小于100的改为0,像素值大于200的改成255,其他像素值乘以2再减去60,然后进行各分量的组合得到新的图像。 2、程序编写: 本程序主要运用for循环语句,和一些基本的函数库:imread(读取图片)、cat(进行RGB各分量的组合)、imshow(绘制图像)。采用的图片为RGB彩色图片,像素大小为512×480,文件命名frutis.jpg,如下: (1)RGB分量的读取 %读取分量 rgb_image=imread('fruits.jpg');%读取图片 fR=rgb_image(:, :, 1);%读取红色分量 fG=rgb_image(:, :, 2);%读取绿色分量 fB=rgb_image(:, :, 3);%读取蓝色分量 (2)RGB分量的变换 %对红色分量进行变换 fR2=double(fR);%转换为双精度浮点类型 for i=1:1:480 for j=1:1:512 %遍历 if(fR2(i,j)<100) fR2(i,j)=0; %像素小于100的等于0 elseif(fR2(i,j)>200) fR2(i,j)=255; %像素大于200的等于255 else fR2(i,j)=2.*fR2(i,j)-60;%其他的像素点乘以2倍再减60 end end end fR2=uint8(fR2);%强制将数据转换为8位无符号整数 %对绿色分量进行变换 fG2=double(fG);%转换为双精度浮点类型 for i=1:1:480 for j=1:1:512 %遍历 if(fG2(i,j)<100) fG2(i,j)=0; %小于100的等于0 elseif(fG2(i,j)>200) fG2(i,j)=255; %大于200的等于255 else fG2(i,j)=2.*fG2(i,j)-60;%其他的像素点乘以2倍再减60 end end end fG2=uint8(fG2);%强制将数据转换为8位无符号整数 %对蓝色分量进行变换 fB2=double(fB);%转换为双精度浮点类型 for i=1:1:480 for j=1:1:512 %遍历 if(fB2(i,j)<100) fB2(i,j)=0; %像素小于100的等于0 elseif(fB2(i,j)>200) fRB2(i,j)=255; %像素大于200的等于255 else fB2(i,j)=2.

备战双十一·尖货优品实时选技术

1. 双十一背后的技术 双十一是全国人民的购物狂欢节,但是对于阿里技术人而言,双十一则是一年一度的大考,技术人穷尽一切办法保障极致的用户体验和稳如泰山的可靠性,从底层网络、基础架构、容量规划、性能优化到个性化推荐,智能搜索,复杂营销玩法,整个技术支撑体系的每个层面都不断演进和诞生大量技术创新。 弱水三千只取一瓢,如果你关注双十一,你会发现有大量的类似下面第一张图的“运动尖货”会场页面,这类会场有两个特点: 特征相似。(例如图1的都是运动类商品) 千人千面。(每位用户看到的商品都是个性化的,进而最大化提升成交概率) 如何从数亿商品中精准的选出满足会场诉求的商品,并且以个性化的方式投放给消费者,最终实现成交概率最大化?背后的技术支撑系统我们称之为“选品投放系统”,本文主要介绍闲鱼选品投放系统的技术演进,希望能给你带来一些解决这类问题的思路。 2. 闲鱼选品系统演变 2.1 选品系统解决的业务问题 闲鱼商品跟大多数电商系统类似,都存在三个核心环节: 商品发布,卖家将需要售卖的商品发布到平台。 商品展示,平台通过各种途径将合适的商品展示给合适的买家,买家通过商品浏览形成购买意图。 商品交易,卖家确定购买意愿后,下单购买商品,商家发货,以及售后等完成钱物交换的所有环节。 选品系统解决的问题主要集中在商品展示环节,尤其在类似双十一这种大型的活动中,选品系统能够将运营同学对行业深入理解跟算法个性化进行有效的结合,构建大量的会场和频道,精选出优质的商品呈现给消费者。 选品系统大体上分为上图所示的三层。 基础数据层。所有的商品相关的数据,其来源极为丰富,可能是卖家发布的商品基础信息,例如品牌,尺寸;也可能是算法对商品的理解和分析,例如图片质量,商品质量;也可以是统计维度的数据,例如商品浏览量统计,商品好评率统计等。通常,基础数据层的数据量级决定了后面技术架构的选型。 运营经验层。运营通过设定各种不同的选商品的规则(简称:选品规则),从海量商品中选出体现其意志的商品集合。例如运动尖货会场,运营可以按照运动品牌品牌,优质卖家等作为选品规则来圈选出运动尖货的基础商品集合。通常,这个集合的数据量级已经比基础数据减少了几个数量级。 算法能力层。在运营选出来的商品集合中,通过推荐引擎,结合用户个性化信息进行商品推荐产生用户看到的会场页面的Feeds流。算法能力层核心就是对运营圈选出商品集合中的商品通过不同的排序算法策略,将对用户而言最可能产生购买意图的商品排在前面。 针对闲鱼的业务场景有一个不同于其他电商的显著的特征:闲鱼商品都是孤品,一旦有人购买,商品就不能再继续售卖,需要从feeds流中排除;同时,新发商品或者商品本身特征的变更,一定要即时影响到下游选品结果集合。总结而言,闲鱼选投系统的核心差异化诉求就是:秒级实时性要求 。 2.2 基于搜索的选品实现 闲鱼早期,同很多初创公司一样,平台上的商品数量比较少,也没有专业的算法团队,但是选品诉求依然大量存在,例如,6月份大学生毕业的时候,组织“毕业季”活动,选品条件是:卖家身份是大学生,商品标题包含“毕业”,商品属于书籍,电器,服装等品类,价格在300元以下。买家浏览的feeds的排序条件是按照距离远近排序,优先看到距离自己最近的。 在当时的闲鱼技术架构下,搜索几乎是所有feeds类页面的数据源提供者,选品,自然而然的就是基于搜索来做。 用户发布商品后,完成商品库写入后,引用发送异步消息给消息中间件,消息中间件采用阿里现在已经开源的RocketMQ[1]。 应用B接收消息中间件的消息后,会从其他应用通过rpc调用获取dump表所需的商品基础信息外的补充信息,并且进行一些数据转换,合并等动作后组装成用于更新搜索引擎的数据结构,先写入mysql承载的搜索dump表中,然后通过http接口调用搜索引擎暴露的实时索引更新服务进行索引实时更新。 每晚,定时调度任务还会触发搜索的全量dump,就是把搜索dump表中的数据拉取到引擎侧,然后完成全量索引构建和线上版本替换的工作。 建设后台运营选品页面,将搜索可以支持的条件构造成一个表单,运营同学可以在表单上选择和组装条件,并且预览组装条件下的选品结果,调整满意以后,就可以保存搜索条件发布到生产系统。 前端页面的feeds请求,则是基于选品配置的id来获得选品规则,翻译为搜索查询串,发送请求给搜索系统获得feeds结果。 搜索引擎选择Solr,除了当时业务量小外(数据量,查询qps都不高),主要是由于当时公司内有个团队基于solr构建了一套针对中小数据量业务的搜索平台,直接接入节省了很多运维和可靠性保障的工作,搜索引擎可以选择ElasticSearch或者其他顺手的搜索引擎。 前面提到,闲鱼商品孤品特性要求我们选品平台一定要满足实时性,在这个阶段,我们保证实时性的最核心动作就是优化实时索引更新可见的时延,原生solr当时在实时索引更新上还存在诸多问题,搜索团队进行了很多优化工作,详细可以参考这篇文章的分享[2],最终我们做到实时索引更新到前台搜索可见时延在100毫秒。 虽然这个选品的架构略显简陋,但是在很长一段时间内支撑了我们的选品诉求,而且即使到现在,这种架构对于中小型的公司,依然具备参考价值。 在阿里内部,依然有很多基于搜索的选品平台存在,一般都会结合算法推荐层来构建,搜索引擎承载的核心作用是: 1. 基于条件的选品结果实时预览 2. 基于条件导出给算法用的商品集合 通过将选品结果集合从搜索引擎导出,写入到KV存储中,推荐算法在进行推荐的时候,从这个结果集合中做数据召回,然后再结合用户行为和其他算法数据进行排序。算法模块的详细工程支撑,将在下文介绍。 注意这个架构示意图中红色字体部分,选品结果数据导出是采用拉的模式,意味着选品结果集合的kv存储的更新只有两个途径: 当新建或者更新一个选品规则的时候,触发系统从引擎拉取规则命中的数据写入到KV存储中。 每天凌晨业务量低的时间段,定时调度任务将生产环境配置的所有选品规则执行一遍,并将结果写入到KV存储中。 这就意味着,商品上新的变更是无法实时更新到选品结果集合中的,几种可能解决思路: 定时的全量执行数据导出。不可行,因为全量导出数据量大,执行时间长,对系统压力大,而且无论如何都做不到秒级全量持续导出和重算。 增量数据导出。不可行,以为引擎本身是实时更新的,即便相同规则,基于索引时间戳的增量召回也可能导致数据重复,而且当规则多的时候,性能上也会快速出现瓶颈。 闲鱼对选品秒级实时性要求的特点,决定了这种模式的的选品方案对闲鱼是不可接受的。但是对于商品库存多,商品变化比较少,对实时性要求不高的电商系统,这种方案完全满足业务诉求,读者可以思考下即便多库存,依然可能存在商品售罄,被处罚导致的下架的情况,这些情况下如何保证最终投放给用户的feeds中有效剔除这些商品? 2.2 基于离线计算的选品实现 我们把类似搜索引擎提供的在线实时数据查询服务称为在线服务,那么离线计算是指基于大数据计算平台,通过提交计算任务,完成大规模海量数据的复杂计算和计算结果的产出。 这种架构下,核心的计算逻辑全部在大数据平台上通过定时任务来执行所有的选品规则,可以充分发挥计算平台的能力,执行超大规模和复杂度的计算,不需要额外搭建搜索引擎等辅助系统。 大数据计算平台有很多种,阿里内部目前主要使用的MaxComputer平台[3],当然也可以自建Kafka(数据采集通道)+Hadoop集群+Hive(SQL查询)+spark(可编程访问及批处理)这样的大数据系统,用于支撑海量数据处理。 显而易见,这种模式下,依然很难满足闲鱼秒级实时性要求。 2.3 实时选品系统的核心链路及其技术挑战 总结前面两种不同选品方案,要实现满足闲鱼业务诉求的实时选品系统,可以归纳下面的核心链路。 实时更新的商品数据宽表。 宽表的含义是列特别多的表,需要把各种数据源产生的可以用于选品规则计算的数据,以独立列的形式实时写入到这张宽表中。 挑战1,需要支持独立字段级别的增量和全量数据合并。 因为选品平台数据源来源多样,并且产出时间不一。 例如闲鱼商品发布过程中不强制要求用户选择类目信息,而是基于用户的输入的标题描述和图片,通过在线算法服务进行实时类目预测,但是在线类目预测算法是以牺牲精准度来保证实时性的,因此,算法通过离线大数据计算平台,每天还会进行全量商品的类目高精度重新预测,这是每天原始数据要进行全量和增量两种模式导入选品数据宽表的原因,是兼顾数据一致性和数据实时性的解法,大部分的实时搜索引擎都是采用类似的解法,全量和增量数据dump相结合的方式来完成索引数据和db数据的同步及实时更新。 只要存在增量和全量更新,就必然存在增量和全量数据合并的问题。 搜索引擎的常见解法是,两个在线服务引擎,引擎1采用实时增量模式运行,引擎2完成全量数据dump后,根据全量数据最晚时间戳,将时间戳之后收到的增量变更消息进行回放来更新增量索引,直到增量数据追平引擎1的增量消息时间戳,然后线上服务执行引擎切换,引擎2提供线上服务,引擎1执行引擎2完成的全量和追增量动作,这种模式能保障线上服务的基础上,完成全量增量的数据合并。但是根据前面的介绍,我们直接用搜索作为选品引擎是是无法满足实时选品诉求的,而其他的数据库不具备这种线上切换索引的能力。 上图展示全量和增量数据在某个字段上叠加冲突的情况,当全量预测完成后执行宽表数据合并的时候,需要能够准确判断类目这个字段的增量和全量如何更新。 挑战2:亿级全量数据更新带来的对宽表的超高写入速度(20W+),读取速度(20W+)。计算公式:10亿数据1小时内完成更新,tps27W。 在线选品规则实时计算。 任何一个商品上的任何一个字段的变更,都需要参与选品规则的计算,来决定当前规则是否依然满足条件,进而决定下游选品结果集合是否需要更新。 挑战3:选品规则执行效率。 新建选品规则全量数据实时计算和预览。当新建或者修改选品规则的时候,需要能够对所有商品基于新的规则进行计算,获取满足规则的商品集合。这里的要点在于,全量商品的计算需要秒级完成计算,并且全量数据本身是实时数据。

京东选品平台实践

1. 背景 随着互联网业的发展和用户购物习惯的转变,电商在零售市场中的占比逐年增加,市场的扩大也带来了各个电商平台中商品的数量在近十年里快速上涨,以京东零售为例,现在全站的商品规模已经达到数十亿级。 如此大的商品量,在带来了更丰富的商品的同时,也给日常电商的运营工作增加了更大的难度。其中很核心的难点之一就是,如何从这些海量的商品中找出优质的、符合运营诉求的商品。 基于这样的痛点,各大零售平台都在近几年推出了各自的选品工具或者平台,本人所在团队有幸参与到了京东零售营销端的选品平台从零到一的规划、设计、落地,并在2022年618大促活动中覆盖了50%的促销活动楼层商品的选品职责。 本文将分享从2021年Q3到2022年618这一年时间里平台开发过程中团队所积累的一些相关的技术经验,希望对业内同学有所帮助。 2. 选品核心能力 从上一节的背景中,我们可以看出一个选品系统最核心的功能是能帮助运营从较大规模的数据中选出目标数据,这是我们进行系统设计最核心的关键点。所以这里设计的关键问题就可以转化为如何能实现从较大规模的数据中选出目标数据。关键问题清晰之后,我们其实可以看出,这是一个数据检索服务。当我们把问题转化成实现一个数据检索服务的时候,很多设计思路就清晰了起来。 检索服务对于每个人来说都不是一个陌生的功能,我们在日常工作设计甚至生活中都经常接触这样的功能,比如日常工作中筛选excel表格中的数据,或者我们日常在百度、谷歌上使用的搜索功能,其实都是数据的检索服务。基于此,我们把各种检索服务进行横向对比分析,可以得到我们认为如果要设计一个选品系统最重要的三大核心要素:数据、筛选和排序。 为了让大家更容易理解这三个核心要素,我们基于三要素把日常经常接触的工具进行横向比较,如下表: Excel百度/谷歌搜素引擎MySQL数据库数据表中数据互联网上的资源库表数据筛选筛选功能搜索词输入where语句排序排序功能个性化or时序order by语句 3. 京东零售选品业务情况 乔布斯曾经在一次发布会上回答了一位工程师质疑他是否懂技术的问题,他回答大意是:我们应该为了一个好产品去找到适合它的技术,而不是为了推广技术而去设计一个产品。同样的,为了更合理的设计好我们的选品平台,我们也需要在前期深入的去了解业务的具体使用场景和相关的技术情况。 经过我们对业务的调研,大体总结出几个核心的业务使用情况: 1. 不同的选品业务会使用不同的数据,数据范围从百万到亿级不等,使用到的指标也不一样。 2. 京东零售业务比较复杂,平台需要支持的业务会比较多。 3. 数据选品需要实时得到结果,结果包括数据的列表和数据的一些分布。 针对上述的业务使用信息,我们可以得到系统需要满足: 1. 支持较大数据量的实时查询。 2. 选品数据多样性高,需要针对不同业务进行可以灵活调整。 3. 需要同时支持OLTP和OLAP查询。 4. 选品领域模型设计 针对上一节的业务使用诉求,我们首先设计了一套选品平台的领域模型,主要包含输入和输出两大部分,输入域包含我们选品的核心三要素:数据、筛选和排序;输出域偏向业务功能的使用诉求,主要包含视图能力和数据输出能力。模型设计如下图: 5. 选品系统架构 确定了选品平台的领域能力模型后,我们继续进行系统架构的设计拆解,由于我们平台的定位是服务整个京东零售营销的选品场景,业务场景较多且区别较大,于是在系统设计上如何通过一套底层能力支撑多变的前台使用是我们在设计平台架构的时候重点需要思考的问题。下面介绍一下团队针对选品从前端到服务端各个环节的系统架构。 5.1 前端 前端是最直接面向用户的一层服务,这里需要先考虑到合适的用户体验,经过一段时间的打磨,最终我们选品操作工作台的交互功能设计了三大核心工作区域:筛选规则配置区、排序配置规则区和展示区(商品列表和商品分布),如下图: 在技术实现方面,为了保证我们整个前端工作区域的适配性和多样性,我们把工作台各个区域的渲染都通过配置化的方式实现,整个配置化组件底层协议基于Json schema,渲染基于京东零售的水滴组件(已开源,水滴表单组件 https://github.com/JDFED/drip-form,水滴表格组件 https://github.com/JDFED/drip-table)。 这一套设计保证了我们可以通过配置快速搭建各个基于同一底层的不同的前端选品样式,具备优秀的灵活性和可适配性。架构图如下: 5.2 服务端 服务端方面,首先是应用层设计,这里最重要的是联动配置化的前端协议来实现后台的服务。考虑到选品本质是上把前端用户交互翻译成数据Query的过程,所以这里对于服务端的应用层最核心的就是两部分功能:协议字典、Query解析引擎。其中协议字典主要作用在于和前段的配置协议进行映射翻译,翻译成一些逻辑语言,比如大于、小于、等于等。Query解析引擎作用是把逻辑性语言通过动态Query的方式生成Query语句。如下图: 在应用层之外,选品服务端的数据层也是非常重要的部分,在存储介质方面,考虑到选品用户需要检索商品以及查看商品分布,技术选型上我们首选ClickHouse。ClickHouse在OLAP查询方面以及数据写入、数据查询性能方面都有很好的表现。 另外,选品数据处理涉及大数据海量数据的前置处理,这里我们主要使用离线大数据计算的方式进行处理(HIVE SQL或者Spark)。在离线数据处理方面,我们主要进行了标准化设计,沉淀了一套通用的数据脚本,把所有数据处理过程都抽象成一套标准的数据处理流程(1. 底池初始化,2. 指标添加,3. 离线导数,4. 数据清理),这样可以保证各个环节可以用通用的数据处理脚本,不同业务处理数据只需要传入不同的配置参数即可。如下图: 最后,在应用层和数据层之外,我们也设计了质量监控体系,包括服务链路监控、定时巡检、降级限流、异常数据处理等,来保证整个选品系统的健壮性和内部流程的可观测性。 最后是整个的架构图,如下: 通过这一套系统架构,我们实现了选品平台的统一底层、灵活配置化的前端,一键部署多端适配的系统特性。 6. 选品数据索引架构 除了上一章节介绍的平台工程架构以外,数据也是选品平台极其核心的部分,这里数据包含数据的生产传输和数据的检索查询。考虑到数据的量级(亿级),传统的单点数据库支持不太适用,我们选择的方向是分布式数据库或者数据引擎,考虑到这里对于查询有明确的聚合查询场景(查看分布等OLAP性质查询),我们综合下来选择了现在社区比较活跃并且成熟度也较高的ClickHouse所谓数据索引引擎。 在索引结构设计上,我们也可以从查询由近到远的视角拆解来看。 首先第一部分是离查询最近的索引,这里索引最核心的指标是提供尽量快的查询性能,考虑到一个选品查询的过程本质上是条件查询的过程,所以这里我们设计上针对不同的选品垂直业务场景,把商品主键和业务指标合并成一个宽表的形式,这样查询可以直接命中单表结构,不需要额外的实时关联数据操作(比如多表join),在性能上是最优的。结构如下: 这里的结构是比较简单明了的,但是我们也要认识到底层的数据结构其实是很多样的,所以如何能保证把多样性的底层数据可以标准化的处理成我们需要的结构是整个数据处理流程中最重要的设计点。针对这块设计,按照数据的实时性要求,我们可以拆分成两大类数据处理流程:离线数据(实时性要求不高,可以容忍小时级或者天级数据延迟)和实时数据(实时性要求高,基本需要准实时)处理流程。 首先看离线数据处理流程,这里的设计思路比较明确,只需要通过离线数据处理脚本把多样的底层数据处理成需要的格式。这里最大的挑战在于当数据量很大的时候如何可以较快的导入到索引库里,这里主要通过一些脚本的优化,比如通过自定义Hash函数把数据进行分区,再各个分区数据直连索引库分片的方式进行数据写入。 接着看实时数据处理流程,对于分布式大数据量,实时数据处理流程的复杂度是高于离线数据处理流程的。实时数据处理的难点主要在于大量数据如何按照我们的标准格式快速接入到查询索引里。为了达成这个系统设计目标,我们参考了业内很多的分布式数据库设计思路,把实时数据处理流程分成两阶段,写入阶段和合并数据阶段。 其中写入阶段目标是把数据能够较快的落库,考虑最核心的是性能,所以我们采用的方案主要是按照原数据流格式直接不做复杂逻辑处理就进行直接入库,整个数据的格式比较灵活。合并数据阶段目标是把数据处理成目标格式,所以这里的服务处理可以做一定的定制处理,来把多样格式的数据处理成统一的目标格式。 通过这样一套底层索引的架构设计,我们通过宽表的查询索引表结构保证了选品实时查询的效率,通过实时和离线双路流程保证了数据的同步传输效率。下图为整体架构图: 7. 结语 京东零售选品平台初版上线于2021年Q3,整个平台的架构设计,包含了系统工程和数据处理两大方面的研发知识体系,对于团队和我个人是一个挑战和机遇。通过这次平台的落地过程,团队完成了很多成绩也踩过很多坑,相对于完成的成绩,我们更感谢这些出现过的问题和踩过的坑,因为团队正是从这一个一个的困难问题中得到了历练,不管从技术深度还是广度上都提升了很多。

京东云ClickHouse和ES双引擎设计在零售选品中的应用实践

背景介绍 涅槃选品是京东零售内的战略级bigboss项目,项目主要致力于构建商品底层能力,打通提报、投放流程,实现选品的线上化、规则化与智能化;通过多方协作盘货,充分表达营销、品类、运营/采销等多方意志。 业务上的多样化需求,导致在项目初期面临以下众多技术难点与挑战。 面向研发排障的问题解决 为解决以上技术难点,京东零售整体设计了一套这样的技术方案: 技术方案在数据存储查询上主要分成三个大模块: 模块一:ClickHouse与Elasticsearch存储结构设计模块; 模块二:ClickHouse数据推送与校验模块; 模块三:Elasticsearch数据推送与校验模块。 一、具体技术方案 主要解决的问题分为三点,第一点是解决快速筛选、快速多维统计查询两项不可兼得的问题,第二点是解决海量商品特征数据导入效率低的问题,第三点是解决海量商品特征数据占用存储资源较高的问题。本场景是一个商品规则化选品平台的项目,电商平台上有数百亿的商品,每一个商品都具有不同的特征数据,平台会持续发布一些营销活动,店铺可以提报部分商品参与这些营销活动,以达到平台营销、商家卖货的目的,而一个商家想要对本店铺的商品进行精准提报的话,就需要根据一定的规则选出目标商品,并且期望这些商品提报后能收到很好的效果;为了满足这一需求,会计算出全量商品的特征数据,全量商品数据量大概在百亿级别,通过前期的一些粗过滤,排除掉那部分很明显不适合参与活动的商品后,最终生成一个大宽表,包含数亿商品和数百个标签。 一般的做法是将数据直接导入数据库,或者是对数据进行一些预处理后导入数据库,提供给到检索平台进行查询,但是每种数据库都有其专长,几乎没有一种数据库在同时满足快速简单筛选的同时还能满足快速多维统计的查询需求;另外,大量的筛选任务需要历史数据,随着项目周期增长,历史数据占用大量存储资源的同时,还会影响整体查询效率。 本文提出Elasticsearch结合ClickHouse的方法,在存储上提出快照表的概念,基于Spark对Elasticsearch和ClickHouse进行离线数据导入和校验的方案,在仅保存两份全量最新数据的情况下,大幅降低了存储资源占用,兼顾了快速筛选和多维度统计查询,同时又能快速导入商品特征数据,极大的提高了数据的更新时效。 具体方法如下: 1、ClickHouse与Elasticsearch存储结构设计,具体方案细节如下: a、存储上采用ClickHouse结合Elasticsearch的方案,主要是为了兼顾快速筛选(多基于Elasticsearch进行)的同时,还能进行快速多维统计查询(多基于ClickHouse进行),双存储引擎首先会遇到一个问题,就是两份数据的一致性问题,本发明通过在ClickHouse和Elasticsearch数据导入阶段进行数据验证来保证数据的一致性; b、检索平台在进行数据查询的时候,在时间范围上分为两种,一种是新任务的实时查询,针对这部分任务,本发明在ClickHouse和Elasticsearch中分别建立一张表,ClickHouse每天生成一张新表,该表包含每个分片上的分布式表和本地表,分布式表用于进行数据查询,本地表设计为ReplicatedReplacingMergeTree引擎,用于数据导入,每日最新数据导入完成并数据校验通过后会清除该表的历史数据;Elasticsearch每天根据商品的类目信息分类,生成一批索引,这里之所以不用一个索引,是因为一个索引中数据量过大会影响查询效率,每日最新数据导入完成并数据校验通过后会清除历史索引的数据; 另一种是历史任务的实时查询,这部分查询需要用到历史数据,针对这类查询,本发明设计出一套快照表的概念,具体方案细节是:每日凌晨会针对前一天新建的任务进行一次遍历查询,获取到具体的商品id后,在数据仓库中进行加工,最终获取到前一天新建任务的全量商品特征数据,这部分数据不会再发生更新,是前一天新建任务的一个快照,在ClickHouse和Elasticsearch中分别建立一张快照表进行存储,与每日存储最新数据不同的是,Elasticsearch中的快照索引是根据快照数据中的任务信息生成的一批索引,不再是根据商品的类目信息,因为后续所有针对快照数据的查询,均是在一个任务范围内,这样设计能实现能快的查询效率。 c、除了上述两种时间范围上的查询,本场景还存在一种二次选品的实时查询,二次选品是指在历史任务的基础之上,再次进行简单的筛选,获取目标商品,这种选品场景比较特殊的是要用到一部分实时标签,针对这部分实时标签的存储设计,本发明采用了Elasticsearch的父子文档;具体方案是:每天在Elasticsearch中根据任务信息生成一批索引(架构图中的回流表),存储历史任务的商品特征数据,与快照不同的是,这批索引每天存储尚在有效期内的全量历史数据,并且索引采用的是父子文档结构,每天离线数据导入完成并数据校验通过后会清除历史索引数据,离线任务数据导入索引父文档,Structured-streaming任务会实时对子文档中的标签进行更新,这么设计,是因为父文档中存在数百个标签,每次更新效率低下,将仅有的几个实时标签放入子文档中更新,效率会比较高。 2、ClickHouse数据推送与校验 ClickHouse数据推送与校验架构流程图如下: 具体方案实施细节如下: a、每日在数据仓库中对商品、用户、流量等数据进行加工融合,生成所需商品的特征数据,最终产生一张特征数据宽表; b、启动Spark任务,首先读取到上一步产生的数据宽表,对数据进行处理,主要包含:根据配置文件中的ClickHouse表字段类型,对每个标签字段进行类型转换,对空值进行填充处理(ClickHouse表默认不能存储空值),对需要存储为Array、Nested等结构的字段进行特殊处理、格式转换等; c、Spark任务从配置文件中获取到需要在ClickHouse中创建的表元数据信息,在ClickHouse集群中首先进行检测,查验最新表是否存在(分布式表和本地表是否都存在),如果存在则先进行数据删除(清除当天的误写的错误数据,不是历史数据),然后校验当前表的结构和配置文件是否一致,不一致则进行字段删除、字段增加等操作,保证表结构和配置文件一致;如果表不存在,则新建表,首先根据配置文件新建ClickHouse集群每个节点上的本地表,本地表引擎为ReplicatedReplacingMergeTree,而后根据本地表新建分布式表,本地表引擎设计为ReplicatedReplacingMergeTree主要有以下目的:一是利用Zookeeper的能力,保证ClickHouse每个分片中的副本间数据一致,这样数据导入只需要导入每个分片中的一个节点即可;二是利用ReplacingMergeTree引擎的能力,在数据导入完成后,进行optimize操作,来保证每个节点上没有重复数据; d、对ClickHouse的表进行新建或更新完成后,Spark对读取到的数据,依据数据主键字段进行数据分配(对主键进行hash,再对ClickHouse的分片数量进行取模),以保证每个分片上的数据具有相同的规则,然后对分配好的数据进行repartition操作,将数据集控制到集群能接受的并行度,最后在Spark的Driver端多线程并行启动数据推送程序,利用JDBC的PreparedStatement按一定批次将数据写入ClickHouse表,以降低Spark对ClickHouse的请求频次; e、在每个分片上的数据推送完成后,Spark会按照既定的规则对ClickHouse中的数据进行验证,本发明以商品的类目维度进行校验,即查询ClickHouse中所有类目下的数据量,和Spark从仓库中获取到的数据量进行校验,校验过程中会出现以下三种情况: 一是ClickHouse与仓库中统计到的数据量一致,那么当前类目数据验证通过; 二是ClickHouse中统计到的数据量要大于仓库中统计到的数据量,这时对当前分片的本地表进行optimize操作,合并数据后,再进行数据验证; 三是ClickHouse中统计到的数据量要小于仓库中统计到的数据量,这时对当前分片本地表中当前校验类目的数据进行重新推送,推送完成后再进行数据校验; 采取分维度的方式进行数据校验,能便于发现数据导入中的出现问题、及时高效的完成数据导入和校验;在整体数据校验通过后,Spark任务会将当前的时间版本回传给数据检索平台,告知ClickHouse中的最新数据已可用,然后对前天的历史数据进行清理,降低整体的存储资源占用。 该方案同样适用于快照数据、二次选品等数据的导入,仅是数据清理策略上不同。 3、Elasticsearch数据推送与校验 Elasticsearch数据推送与校验架构流程图如下: 具体方案实施细节如下: a、每日在数据仓库中对商品、用户、流量等数据进行加工融合,生成所需商品的特征数据,最终产生一张特征数据宽表(该步骤与ClickHouse数据推送与校验中的第一步共用); b、启动Spark任务,首先读取到上一步产生的数据宽表,对数据进行处理,主要包含:根据配置文件中的Elasticsearch索引字段类型,对每个标签字段进行类型转换,用ClickHouse导入模块中相同的方式对空值进行填充处理(保证与ClickHouse中的数据一致性),对需要存储为Array、Nested等结构的字段进行特殊处理、格式转换,当推送的索引为父子文档时,还需要对数据集进行重组,以满足父子文档的数据结构; c、Spark任务对数据集进行数据分维度统计,以便于创建一系列的索引,本发明是对数据集在商品类目维度上进行统计,得到每个类目的数据量后,依据当前Elasticsearch索引最新的配置信息,在Elasticsearch集群中创建既定数量的索引,再依据一定的算法逻辑,将每个类目分配到其中的一个索引上,保证同一类目的商品数据一定处于同一个索引中,而且每个索引的数据量尽可能的均匀;这样设计的目的是为了避免一个索引中数据量过大影响查询效率,同时能一定程度上提升整体的查询并发性能,而且该方案可依据业务体量进行横向扩充,比如增加集群数量; d、从上一步中获取到了数据集每个类目的Elasticsearch索引归属信息,依据该关系,Spark任务对全量数据集进行分桶处理,每一个数据桶中的数据全部属于同一个Elasticsearch索引,分桶完成后基于Elasticsearch的Bulkprocessor方法,将数据批量的写入Elasticsearch,整体的写入逻辑是:以数据集的主键为Elasticsearch索引的_id,多集群的索引并行写、同集群的索引串行写;采用这种方式能避免同一个Elasticsearch集群存在多个写入点,导致大量reject,致使数据写入效率低下的问题,而多集群不存在共用写入点的问题,可以采用并行写来提升写入效率,同时以主键为_id,能避免数据写入重复的问题; e、在每个索引的数据推送完成后,Spark会按照既定的规则对Elasticsearch中的数据进行验证,本发明以商品的类目维度进行校验,即查询Elasticsearch集群每个索引中所有类目下的数据量,和Spark从仓库中获取到的数据量进行校验,校验过程中会出现以下两种情况: 一是Elasticsearch与仓库中统计到的数据量一致,那么当前类目数据验证通过; 二是Elasticsearch中统计到的数据量要小于仓库中统计到的数据量,这时对当前类目的数据进行重复导入,数据导入完成后,再进行数据验证; 采取分维度的方式进行数据校验,能便于发现数据导入中的出现问题、及时高效的完成数据导入和校验;在整体数据校验通过后,Spark任务会将当前的时间版本回传给数据检索平台,告知Elasticsearch中的最新数据已可用,然后对前天的历史数据进行清理,降低整体的存储资源占用。 该方案同样适用于快照数据、二次选品等数据的导入,仅是数据清理策略上不同。 二、技术方案实施流程 具体流程如下: 三、测试结论 目前全量商品特征数据超过10亿,共490个标签,每天离线导入ClickHouse用时40min(40个分片),相较之前直写分布式表的方式,导入耗时平均降低80%;每天离线导入Elasticsearch用时2小时(单集群,可横向扩充),相较单索引写入的方式(偶尔会写不进去),导入耗时平均降低60%;在支持简单筛选和上下钻、top、窗口查询、多维度排序、关联聚合等复杂查询的同时,线上检索平台qps最高能达到300左右,tp99在毫秒级别;相较普通做法,本方案的方法将存储资源降低了60%-70%。 未来展望 该技术方案自项目上线以来,支撑了多场景、多业务方、多样化的选品流程,为整个选品的规则化、线上化、智能化提供了数据和索引的底层能力,虽然该方案满足了目前多方业务的切实需求,但是仍然存在很多优化点、扩展点待改进,具体如下: 一、双引擎的设计,虽然使目前这一套复杂的选品平台能够在巨量级数据(10亿实体、600+标签)上兼顾了快速筛选和复杂计算的能力,但是也会导致一个比较致命的问题,那就是双引擎数据一致性的问题,目前采取的方式是采取同一套默认值,数据更新后进行校验,但是每天校验的时间一定程度上影响了整体的数据更新时效,因此,这一块是后续需要去优化的一个比较重要的点。 二、目前整套系统600+标签,99%都是离线标签,实时标签仅有个位数,但是一个好的选品平台,肯定需要大量实时标签的加持;实时标签的写入、更新、索引建立,和离线标签比较起来有很大的不同,对上述所提到的数据一致性也会带来比较大的挑战,甚至是影响整个数据索引底层的架构设计。

linux 防火墙systemctl (个人笔记)

查看 systemctl status firewalld 开启 systemctl start firewalld 关闭 systemctl stop firewalld.service 查看所有 firewall-cmd --zone=public --list-ports 开放端口:// --permanent 永久生效,没有此参数重启后失效 firewall-cmd --zone=public --add-port=9527/tcp --permanent firewall-cmd --zone=public --add-port=9528/tcp --permanent 重新载入 firewall-cmd --reload 删除端口:// --permanent 永久生效,没有此参数重启后失效 firewall-cmd --zone=public --remove-port=9528/tcp --permanent 查看指定端口的状态 firewall-cmd --zone=public --query-port=80/tcp

Import image from vue with vite configured

I am learning vue.js, in an example like below, but when I run the code, the image can’t display. <template> <img v-bind:src="logo" /> </template> <script setup> const logo = '../assets/logo.png'; </script> When I visit http://localhost:3000, it report the following error: http://localhost:3000/assets/logo.svg not found When I changed .. to @, it still report error like below: http://localhost:3000/@/assets/logo.svg not found And finally I find that I need to use import statement like below:

python 学习笔记20 批量修改页眉页脚

需求:修改指定目录下所有文件的页眉页脚,或者往里面添加内容。 1. 这里做了word的实现和excel的实现,如下: 需要先安装 pip3 install pywin32,另外页眉页脚格式设置可以参考: word: 浅谈Word.Application,关于js操作word文档的使用_new word.application-CSDN博客 excel: Python操作Excel教程(图文教程,超详细)Python xlwings模块详解,_xlwings教程-CSDN博客 import os import xlwings as xw import win32com.client as win32 import pythoncom #将需要替换页眉页脚的文档放到path下 path = r'C:\Users\d\Desktop\pdf改名脚本\22\2022年\test' #原始页眉页脚内容 old_name = u'999' #新页眉页脚内容 new_name = u'888' #替换失败记录日志 err_log = path + u'\\head修改出错列表.txt' def log(text): with open( err_log,"a+" ) as f: f.write(text) f.write('\n') def change_headerfooter(path): ''' 更改文件的页眉页脚 ''' pythoncom.CoInitialize() word = win32.Dispatch('Word.Application') #print(dir(word)) word.Visible = 0 word.DisplayAlerts = 0 exapp = xw.

c++ websocket 协议分析与实现

前言 网上有很多第三方库,nopoll,uwebsockets,libwebsockets,都喜欢回调或太复杂,个人只需要在后端用,所以手动写个; 1:环境 ubuntu18 g++(支持c++11即可) 第三方库:jsoncpp,openssl 2:安装 jsoncpp 读取json 配置文件 用 自动安装 网上一堆教程 openssl 如果系统没带,需要安装下 sudo apt-get install openssl 一般是1.1版本 够用了 3:websocket server 1> 主要就用到 epoll 模式(io_uring 更好点,就是内核版本要高点),3个进程 主进程作为监控进程 2个子进程 一个network进程 一个 logic 进程 2> 子进程间 主要通过共享内存 加socketpair 通知 交换数据 3>websocket 握手协议 先看例子 上前端代码 html <!DOCTYPE HTML> <html> <head> <meta http-equiv="content-type" content="text/html" /> <meta name="author" content="https://github.com/" /> <title>websocket test</title> <script> var socket; function Connect(){ try{ socket=new WebSocket('ws://192.168.1.131:9000'); //'ws://192.168.1.131:9000'); }catch(e){ alert('error catch'+e); return; } socket.

常见的http状态码出现原因200、301、302、403、404、500、503

101 websocket协议 websocket长连接协议,通常用来即时通讯。如视频会议、直播、弹幕等 200 请求被成功处理 成功请求 301 永久性重定向 比如建设一个网站后,将网站的url变换了,重新申请一个域名,但是希望之前的用户访问之前url仍然可以访问到,就可以做一个重定向新的url下面。比如京东最早域名www.360buy.com名重定向到现在www.jd.com 302 临时性重定向 比如用户在未登录时访问个人中心页面,这时可以临时重定向到登录的url。 304 Not Modified 当客户端拥有可能过期的缓存时,会携带缓存的标识 etag、时间等信息询问服务器缓存是否仍可复用,而304是告诉客户端可以 复用缓存。 400 请求出错 由于语法格式有误,服务器无法理解此请求。不作修改,客户程序就无法重复此请求。 401 未授权 (未授权) 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。 403 没有访问权限 系统中某些页面只有在某些权限下才能访问,当用户去访问了一个本身没有访问权限的url,回报403错误。 404 没有对应资源 一般是自己输入了一个url,这个url并不合法。 404 找不到,Web 服务器找不到您所请求的文件或脚本。 请检查URL 以确保路径正确。 405 不允许此方法 405 不允许此方法,对于请求所标识的资源,不允许使用请求行中所指定的方法。(get/post/put/delete/请求用混淆了,更正即可) 请确保为所请求的资源设置了正确的 MIME 类型 406 不可接受 根据此请求中所发送的“接受”标题, 此请求所标识的资源只能生成内容特征为“不可接受”的响应实体 407 需要代理身份验证 407 需要代理身份验证,在可为此请求提供服务之前, 您必须验证此代理服务器。请登录到代理服务器,然后重试 412 前提条件失败 在服务器上测试前提条件时,部分请求标题字段中所给定的前提条件估计为FALSE。 客户机将前提条件放置在当前资源 metainformation(标题字段数据)中,以防止所请求的方法被误用到其他资源 414 Request-URI 太长 414 Request-URI 太长,Request-URL太长,服务器拒绝服务此请求。仅在下列条件下才有可能发生此条件: 客户机错误地将 POST 请求转换为具有较长的查询信息的 GET 请求客户机遇到了重定向问题(例如,指向自身的后缀的重定向前缀)服务器正遭受试图利用某些服务器(将固定长度的缓冲区用于读取或执行 Request-URI)中的安全性漏洞的客户干扰 500 服务器错误 比如服务器某一个函数代码出错了,有没有捕获异常,这时候会报500错误。

七天搞定软件测试,这一篇教程就够了,学完最少能拿13k

前言 在软件开发的世界中,软件测试是不可或缺的一部分。它是确保软件质量、功能完整性和用户满意度的关键环节。本文小编将为大家介绍各类软件测试的奥秘,并提供入门级的指导和见解。 本文内容概要: 软件测试是什么?黑盒测试vs白盒测试自动化测试vs手工测试功能测试方法论非功能测试方法论软件测试生命周期软件测试最佳实践 软件测试是什么? 软件测试是在开发流程中被开发者用来持续地评估和纠正特性的功能性的一个循环进行的步骤。软件测试比对软件的当前构建和软件需求,以确认没有疏漏的需求。同样需要验证的是,软件在跨越不同媒介时、与现有软件集成时运行正确。 软件测试是如何运作的? 测试软件有不少办法。通常来讲,开发者首先决定一个需要验证的行为或者特性,创建一个测试来确认特性,接着要么修改特性,要么通过测试就直接继续后面事情了。 在早期软件设计哲学中,测试经常完全被忽视。现在软件已经变得更加复杂,在更大规模被实现,而且在不同设备与操作系统间各不相同。现代的开发周期中,软件测试已经是必要的部分了。它扮演着QA一种不断发展的形式,验证软件可以对各种可能的使用场景和环境正常响应。 黑盒测试vs白盒测试 软件测试有很多不同类型,每种类型在测试中专攻特定的缺陷。所有的测试类型可以宽泛描述为黑盒或白盒测试。这个区分描述软件测试人员需要掌握的背景知识。 黑盒测试:测试人员知道软件产品应该实现什么而不知道是如何实现的。测试人员仅仅目睹了编程的结果或行为,他们自己不必成为程序员。测试人员经常是开发步骤外部的某些人,给出外部的观点。黑盒测试主要用于测试程序行为和评估用户体验。 白盒测试:白盒测试是黑盒测试的反面,测试人员的确知道软件的内部结构。这些测试人员通过特性测试用例输入的使用来评估源代码里面程序的逻辑。通过追踪这些输入的流动,测试人员可以验证这些测试用例在屏幕背后被正确处理。白盒测试人员常常是开发步骤内的程序员,他们被用于检查源代码的效率。 手工测试vs自动化 测试方法另一个主要分类是手工测试vs自动化测试。很多特定测试方法论可以同时被手工或自动化测试完成。这个区别描述测试是如何被完成的。 手工测试: 手工测试需要一个人类测试人员来扮演终端用户的角色,一次检查一个测试用例。这是测试的传统形式,可以找到自动化测试框架难以识别的问题(web应用元素的表现,令人困惑的布局等)。 自动化测试 自动化测试(或测试自动化)是使用软件的步骤,调用一个测试框架来创建使用期望输出对比当前程序输出的自动的测试用例。最常见的框架是Selenium和Cucumber。 自动测试框架的两个最常见的测试步骤是图形用户接口测试和API测试,前者模拟诸如点击或按键的用户接口事件,后者绕开用户接口来验证底层行为。自动化测试被用于快速执行输出驱动的测试或者为维护测试执行重复的测试用例。 功能测试方法论 现在我们将会讨论通过更加广泛类型区分的测试方法论,功能测试或非功能测试。这个区别描述测试关注的是软件行为还是内部运作。 功能测试 黑盒QA测试的一种类型测试的是从软件需求和说明书生成的测试用例。下方是不同功能测试方法论的一些常见类型。 最常见的功能方法论: 单元测试集成测试系统测试验收测试回归测试冒烟测试 常见功能测试步骤 绝大多数基础测试经历同样的四步,每个步骤测试范围更加宽广。步骤始于评估单一组件的单元测试,终于评估产品和初始计划关联性的验收测试。 单元测试: 单元测试被用于测试和其他组件分离开的程序组件。举个例子,面向对象程序中,你会在尝试连接到其他类前单元测试一个单独的类。这种类型的测试经常是开发者完成的,用于在无需等待完整测试周期下捕捉缺陷。单元测试绝大多数情况是自动执行的,用于快速获取到结果,但是也能手动进行。 集成测试: 集成测试用于测试诸多互相连接的程序组件的协同运行。这个测试经常是在单元测试后进行的,首先独立验证单一组件,然后验证组件协同的运行。 举个例子,你可以集成测试一个父类和两个关联子类来确保测试用于所有预期属性的用例的输入被分配给预期的类。集成测试,通常都是自动化的测试,是开发者完成的,用于验证互相关联的组件无缝衔接。 系统测试: 系统测试是一起使用所有组件来测试完整产品的构建的。当集成测试测试了互相连接的组件的模块后,系统测试测试所有组件集成后程序如何运作,并且在模块内部操作中捕捉缺陷。 验收测试: 验收测试(或用户验收测试)是一个在开发过程后期执行的,用来评估是否所有初始的特定需求是被最终产品构建满足的测试。内部和外部测试者都要评审初始产品说明书和业务需求,然后当他们使用产品时候逐一检查。使用最常见的apha测试(内部)和beta测试(外部)去做验收测试有很多途径。 专门的功能方法论 在上面步骤之外去测试一个程序的特定层面,也有经过微调的功能测试手段。下面是最常见的专门的功能方法论 回归测试 回归测试是在一个更新或改变后用于测试产品集成性的手段。回归测试套件要么在整个程序,要么仅仅在程序变了的部分运行自动测试。套件接着把输出和早期产品构建记录的输出进行比对。如果输出是匹配的,那么测试成功。如果它们以预期方式改变了,那么测试验证了功能有回归或还原。 回归测试是维护测试最常见的形式,因为其检查程序发布后表现如何。回归测试可以被定期执行来提供持续测试。 冒烟测试 冒烟测试(Smoke Testing)是软件测试中的一种测试方法,旨在快速验证系统的基本功能是否正常工作,以确保软件在进入更详细的测试阶段之前是可用的。 冒烟测试通常在软件构建或发布后的早期阶段进行,它会对软件的核心功能进行一系列的简单测试,以发现可能的严重问题或错误。这些测试通常是预先定义的基本功能测试用例,涵盖了软件的主要功能点。 冒烟测试的目标是在系统经过基本构建之后,对其进行表面层次的测试,以确保没有明显的错误或问题。如果冒烟测试失败,即发现了关键功能的严重问题,那么可能需要回退到先前的开发阶段并解决问题,以避免在后续的详细测试中浪费时间和资源。 冒烟测试的优点包括: 快速验证:冒烟测试可以在短时间内快速验证软件的基本功能,帮助发现可能的严重问题。提早发现问题:通过在早期阶段发现问题,可以节省后续测试阶段的时间和资源。提高软件质量:通过确保软件的基本功能正常工作,可以提高软件的质量和稳定性。 非功能测试方法 非功能测试方法测试一个程序如何运行,而不是特定程序表现的成功运行,举个例子,一个非功能测试可能测试的是一个程序在更大规模下如何的运行良好或者当系统运行很长一段时间后表现如何。由于非功能测试定义的主体性,很多非功能测试方法论关注点有所重叠。 常见非功能测试方法论: 性能测试安全测试可用性测试兼容性测试压力测试 让我们深入了解下这些方法论 性能测试: 性能测试是测试的一种常见形式,评估在预设负载下软件的运行速度、响应和可靠性等。如果软件正常运行,但是在这些分类里面任意一个没有满足期望标准,在继续其软件开发周期前,软件将会把打回开发者去提升性能。 安全测试: 安全测试被用于在使用了诸如基于账号的系统或金融系统软件的敏感信息的信息系统或软件中寻找缺点。下面是安全测试中的一些要求: 保密性:敏感信息是受约束的。完整性:数据不能被拷贝或修改。认证:用户比如被验证为是期望的用户。鉴权:用户必须拥有权限来查看敏感信息。可用性:当授权用户需要信息时,必须是可用的。不可否认性:通信两端的用户在发生通信前必须校验各自凭证 易用性测试: 易用性测试用于识别真正的终端用户会在哪里遇到困难或困惑。这个主要是在研究者观察下由一群受控的终端用户进行的。测试者被要求去执行特定任务,比如“创建一个账号”,但是却没有被告诉怎么去完成。他们然后使用产品来完成任务并给出关于体验的高质量反馈。这个方法论允许开发者获取到关于他们程序可用性和直观反应的真实反馈,并且无需很多的说明。 这个与a11y测试联系紧密,a11y测试记录能力各不相同的终端用户能多容易地操作软件。举个例子,文字转语音软件和web应用的可视化元素的交互如何。 兼容性测试: 兼容性测试评估在不同计算环境下软件表现如何。这个通常使用一个测试框架完成的。这种框架使用模拟不同目标设备的很多虚拟机器来执行同样的输入。每个VM的输出被记录和比对,以确认是否所有输出都是一样的并且跨越不同平台时候表现是否有所不同。这种测试确保无论终端用户在哪里使用,都有一致的体验。 举个例子:如果你曾经为iOS和安卓创建了一个移动端APP,你将会需要一个兼容测试,来验证那个APP在两个平台上以相同的预设级别运行。 压力测试: 压力测试是开发者把听他们的软件推送到一个极端测试用例,来验证软件的断点。最常见的压力测试是最大化并发用户来找出当前构建能承载的极限。整个压力测试中性能被完整记录,因此开发者可以发现软件断点,指出可接受级别下合适用户体验会降级。极限情况下,压力测试致力于找出系统在哪里会失效,因此你可以在当前产品版本下规避这些失效条件。 举个例子,设想你正在开发一个在线视频游戏。你可以通过在这个游戏中单次尽可能获得多的在线玩家来进行压力测试。你可以然后记录服务器平台的表现(速率、响应等),同样也能发现何时服务器会崩溃(断点)。 压力测试和负载测试高度重叠。负载测试记录软件在预期负载下的运行。压力测试记录软件在最大负载下的运行。