基于树莓派实现的智能小车

项目介绍 摘要: 树莓派3是一款基于ARM的微型电脑主板,具备所有PC的基本功能,Python作为主要编程语言,系统基于Linux或者Windows 10 IoT,有良好的易用性和多功能性。这里介绍的是如何用树莓派3来实现太原理工大学的毕业设计,该设计是树莓派结合多个传感器的智能小车的发明,是未来多个行业的发展方向,它可以按照程序预先设定好的模式在一个符合设定程序的环境里自动的运作,不需要人为的管理,可应用于科学勘探、科研、军事等的用途。 本系统为实现设计题目的要求,采用了树莓派3为控制核心,接收并处理传感器消息;利用超声波传感器与舵机相结合或使用红外线传感器检测道路上的障碍,控制智能小车的自动避障,并且可以自动记录小车运行速度;利用ssh键盘控制或spp手机app蓝牙遥控或通过手机app遥控。 整个小车系统的电路结构简单(采用树莓派的GPIO为核心省去单片机最小系统的设计),可靠性能高(树莓派的优越性)。实验测试结果满足预期要求,本文将着重介绍了该小车系统的硬件设计方法及软件实现方式以及测试结果分析。 采用的技术主要有: (1) 通过编程来控制小车运行; (2) 传感器的有效应用; (3) ssh通讯、蓝牙spp通讯、wifi通讯. 关键词 树莓派3、超声波、红外、智能小车 效果图 目录: 摘 要 I Abstract II 前 言 1 1.1 树莓派是什么? 1 1.2 树莓派启动方式及支持的系统 2 1.3 镜像烧写 2 1.4 开发板供电 3 1.5 GPIO模块 3方案设计与论证 4 2.1 直流调速系统 4 2.2 检测系统 5 2.2.1 行车距离检测 5 2.2.2 行车速度检测 5 2.3 通讯模块 7 2.3.1 蓝牙通讯 7 2.2.2 WIFI通讯 8 2.3 系统原理图 8硬件设计 9 3.1 树莓派3硬件结构 9

audio之mclk异常分析以及通道映射

1.mclk异常分析 (以调试tlv320aic为例)当录音失败时,需要测量下i2s的信号,包括sclk,lrck,sdi以及mclk;常遇到mclk异常,也就是示波器测量到其频率的波形不稳定,频率大小对不上,电压和幅值也不对,例如下图所示: 设备树上看到的频率为12288000,但实际测量为2.8M;那么在dts中配置上assigned-clock-rates = <12288000>;然后检查下TLV320aic驱动里面,在开启录音的时候,是否有调用到clk_prepare_enable(mclk); 有些codec驱动没有这个clk_prepare_enable,那就自己添加上去验证;驱动修改如下在aic31xx_codec_probe添加:dts和驱动修改后,编译升级固件,此时mclk的波形幅值都是正确的,并且能测量到是12.28MHz,波形也是稳定的 2.mclk没有信号输出 录音时,mclk没有信号输出;首先要确保mclk的引脚是复用正确的,可以通过该指令去查看cat /sys/kernel/debug/pinctrl/pinctrl-rockchip-pinctrl/pinmux-pins;下图可见是正常的,那么mclk这个引脚当作普通的gpio是否可以正常的拉高拉低,如果不行的话,那就是硬件上的问题了。 当mclk的复用,电压之类的都正常,那么录音的时候还是没有波形信号输出,只能再去检查下dts的clock配置; clocks = <&cru I2S3_MCLKOUT>; clock-names = "mclk"; assigned-clocks = <&cru I2S3_MCLKOUT>, <&cru I2S3_MCLK_IOE>; assigned-clock-rates = <12288000>; assigned-clock-parents = <&cru I2S3_MCLKOUT_TX>, <&cru I2S3_MCLKOUT>; #####该问题,mclk没有出来,主要是assigned-clock-parents当时配置为<&cru I2S3_MCLKOUT_TX>, 少了一个 <&cru I2S3_MCLKOUT>; 在驱动代码中可以看到,i2s3有两个clock-parent,如下,代码中找到关键词“CLK_SET_RATE_PARENT”,其对应的有两个 即I2S3_MCLKOUT_TX,I2S3_MCLKOUT; 而assigned-clocks就查找关键字“MUXGRF",其对应了I2S3_MCLKOUT和I2S3_MCLK_IOE; 3.通道引脚的映射 例如一个i2s下面挂载着2个tlv320aic芯片,使用SDO1和SDO2输出,那么此时需要进行通道映射,在i2s的节点下面添加配置rockchip,i2s-tx-route = <2 1 0 3>; 其实是<SDO0 SDO1 SDO2 SDO3>这样的顺序排列, 也就是说把SDO0这个寄存器写入2,也就是使能了path2(56通道),SDO1写入了1,使能了path1(34通道),SDO2写入了0,使能了path0(12通道),SDO3写入了3,使能了path3(78通道);由于一个SDO是2通道,所以需要4通道的音源去播放才行。

服务器负载均衡配置——基于HTTPS流量的服务器负载均衡

目录 一、组网需求 二、网络拓扑 三、配置要点 四、操作步骤 1、基础上网配置 2、配置负载均衡服务器 3、配置安全策略 五、验证效果 一、组网需求 如下图所示,公司内部有2台web服务器,服务器对外提供的域名为www.test.com, 需要通过https进行访问;在防火墙上配置负载均衡,将web服务负载到192.168.1.1 和192.168.1.2 两台服务器之上。 二、网络拓扑 三、配置要点 1、基础上网配置 2、配置负载均衡服务器 (1)配置健康检查 (2)配置负载均衡服务器 (3)配置真实服务器 3、配置安全策略 四、操作步骤 1、基础上网配置 配置详细过程请参照 “路由模式典型功能--单线上网--静态地址线路上网配置“一节: 接口IP如下: 路由配置如下: 2、配置负载均衡服务器 (1)配置负载均衡服务器 菜单: 防护墙>负载均衡>健康检查, 点击“新建”按钮,建立虚拟服务器,如下图所示: 名称: https(该名称为自定义,可根据需要进行修改) 类型:http,tcp,udp,ip等方式,本例选择为https,如果是dns服务器则需要选择udp类型。 接口:port15, 防火墙连接外网的端口。 服务器虚拟IP:服务器对外提供服务的IP,192.168.118.126 负载均衡方法:支持静态,轮询,加权,最早存活,最小响应时间,最小连接数,http host等多种方法 保持方法: http cookie http 多路复用: 可选项,可以将客户请求的多个链接,合并为一条请求来链接服务器,降低服务器的负载。 安全套接卸载:client--RuijieGate客户端与防火墙之间为ssl链接, 防火墙与服务器之间为明文,减轻服务器负载。 client--RuijieGate--server 客户端与防火墙之间为ssl链接, 防火墙与服务器之间为ssl链接。 证书: 导入为服务器申请的证书,本例为网站的合法证书为web。 健康检查: 可选项,只有一个真实服务器,无需选择。 (2)配置真实服务器 菜单: 防护墙>负载均衡>真实服务器, 点击“新建”按钮,建立2台真实服务器,如下图所示: 虚拟服务器: https, 选择为哪台虚拟服务器来建立真实服务器。 IP地址: 真实服务器的ip地址。 端口: 真实服务器http服务端口,可以不与虚拟服务器的服务器端口相同。 权重: 本例不可选,如果选择了基于权重的负载方式,则可以在此处指定全总比如,比如 10:10 等,

F#奇妙游(35):MVC模式和ADT分析

前言 经常在知乎上看帖子,给人的感觉就是桌面开发已经挂了。当然知乎上每天药丸的东西实在是太多了,什么C#药丸啊,感觉上是地球分分钟就要报销。但是在工业界,桌面应用还是有一些市场的,在上位机程序中、在功能非常复杂的桌面应用还是没办法被网页所替代。 就比如说我们用来开发程序的JetBrain系列工具,虽然免费的Eclipse荣光不在,但是收费的IDE居然还能活得好好的。这说明在行业软件中,人们依然依赖界面开发良好的桌面应用来完成信息化的操作。 前几天刚看了一个WPF可能药丸的帖子,说是WPF已经被微软抛弃了。我居然还回头来整MVC,可能也是太没前途了。人家WPF好歹是MVVM。 MVC的内涵 MVVM和MVC其实都是OOP时代对UI程序的开发框架。前者(MVVM)通过分离模型和视图,并把状态和行为结合到一个对象中,称为ViewModel,ViewModel则通过数据绑定来实现视图的更新。而这里面最为核心的行为,则需要通过事件的方式为ViewModel所处理,这种事件处理方式没有一致的机制,可以通过数据绑定,也可以通过注册事件处理函数。此外,ViewModel还必须维护一个运行状态的存储机制,这就带来更高的复杂性。 Owns Owns Notify Update View ViewModel Model MVC分离模型和视图的意图和MVVM一样,此外,MVC还定义了视图和控制器的分离。 Update Events Notify Update Controller Model View 在MVC中,控制器负责处理用户的输入(通常被抽象为事件),然后更新模型,模型更新后,会通过Controller通知视图进行更新。这里的模型和视图都是被动的(模型甚至可能是值),它们不会主动去更新自己,而是被控制器所更新。 这里核心的就是控制器对于事件的处理以及事件的抽象。这里最有意思的是对 于Controller而言,View不过就是一个事件流。 在.NET平台中,采用Observable和Observer模式来实现事件的抽象。这里的事件流就是一个Observable对象(也就是Subject),它的接口是public interface IObservable<out T>。这个接口的泛型类型T就是事件的类型,这个对象提供了事件的相关信息。官方文档中的描述是: 定义基于推送的通知的提供程序。 这个接口规定的方法是Subscribe,也就是把一个观察者注册到这个事件流中。 abstract member Subscribe: observer: IObserver<'T> -> IDisposable 这里的观察者就是Controller,它通过订阅事件流,来接受事件的通知。这里的事件就是View的事件。这样,我们就把MVC中的事件抽象为了一个事件流,这个事件流就是一个Observable对象。 在F#中提供了对于事件驱动的程序设计的支持,对应的命名空间为FSharp.Core.Control。下面的例子就是一个简单的事件流的例子。类型Event实现了IObservable接口,它的泛型类型就是事件的类型。其中Publish属性就是一个IObservable对象,Trigger方法用来触发事件。 IObservable<T> +Subscribe(IObservable<T>) +Add(IObservable<T>) Event<T> +IObservable<T> Publish +Trigger(T) open System.Collections.Generic type MyClassWithCLIEvent() = let event1 = new Event<string>() [<CLIEvent>] member this.Event1 = event1.Publish member this.TestEvent(arg) = event1.Trigger(arg) let classWithEvent = new MyClassWithCLIEvent() classWithEvent.

vue使用sort排序时报死循环错误:you may have an infinite update loop in a component render function

问题产生的原因:你在data中定义了一个响应式变量,而这个响应式变量的状态是通过一个函数来返回的,返回的状态结果要显示在Dom中,而这个函数的内部是一个循环; 问题来了:循环没有及时终止,导致变量一直在更新,而Dom又一直在渲染,无限循环,渲染-更新 卡死; 解决方案 第一种: 具体问题不一样,但都是死循环类型,所以处理方式也是差不多的。就是不直接对响应式数据进行操作,对响应式数据的副本进行排序然后并返回计算结果; 下面是尤玉溪在github上面给出的解决方案;先使用一个空的slice方法,然后在使用sort排序方法; 不能直接使用sort方法;因为sort方法会改变原数组,从而导致多次渲染; 而数组的slice() 方法返回一个新的数组对象,这一对象是一个由 begin 和 end 决定的原数组的浅拷贝(包括 begin,不包括end)。原始数组不会被改变。 所以 代码可以改为: // 排序操作 sortList(list) { let sortList = list.slice().sort((a, b) => { return a.num - b.num; }); return sortList; } 第二种: 与上面的思路相同;深拷贝一下原数组然后再进行排序: // 排序操作 sortList(list) { let sortList =JSON.parse(JSON.stringify(list)).sort((a, b) => { return a.num - b.num; }); return sortList; }, 第三种: 这一种方法也能解决问题,但是比较麻烦一点:不推荐使用 其实出现报错的根源就在于把数组定义到了 vue实例的data里面,因为vue初始化时会把data里面的所有数据都添加响应式依赖;会监听数组的变化然后做出一些渲染;那我把数据不定义到vue实例里面不就可以了吗;看以下代码改动: 我把copyTextList 定义到了最上面;然后对他赋值然后直接进行sort排序;排完之后再次赋值给一个data里面的newList让它进行渲染视图; <template> <div class="list"> <ul v-for="(item, index) in newList"

Langchain里的“记忆力”,让AI只记住有用的事

今天要讲以下内容: 1.ConversationBufferWindowMemory:基于一个固定长度的滑动窗口的“记忆”功能 2.ConversationSummaryMemory:总结对话“记忆”功能 3.ConversationSummaryBufferMemory:上面两个的结合,超过一定token限制之前以对话形式进行存储,超过之后进行小结存储。 4.memory.save_context:有上下文对话,可以通过此插入对话内容,可供后续对话内容 5.EntityMemory:按命名实体记录对话上下文,有重点的存储 1.BufferWindow 我们都知道让AI执行对话,需要给它一定的上下文它才能知道我们聊的是什么事情,而把我们所有聊天的记录传给openAI肯定是不行的,那会耗费有很多的token,所以之前我们的操作则都是限制保存上下文,今天我们用 Langchain的ConversationBufferWindowMemory来实现记忆上下文对话的过程。 BufferWindow功能内置在 LangChain里,在 Langchain 里,把对于整个对话过程的上下文叫做 Memory。任何一个 LLMChain,我们都可以给它加上一个 Memory,来让它记住最近的对话上下文。 #! pip install langchain #! pip install openai from langchain.memory import ConversationBufferWindowMemory from langchain.prompts import PromptTemplate from langchain.chains import LLMChain from langchain.llms import OpenAI import openai, os os.environ["OPENAI_API_KEY"] = "" openai.api_key = os.environ.get("OPENAI_API_KEY") template = """你是一个中国厨师,用中文回答做菜的问题。你的回答需要满足以下要求: 1. 你的回答必须是中文 2. 回答限制在100个字以内 {chat_history} Human: {human_input} Chatbot:""" prompt=PromptTemplate( input_variables=["chat_history","human_input"], template=template ) # k=3保留最近三次对话 memory=ConversationBufferWindowMemory(memory_key="chat_history",k=3) llm_chain=LLMChain( llm=OpenAI(), prompt=prompt, memory=memory, verbose=True ) llm_chain.

Delphi中ClientDataSet的用法小结

Delphi中ClientDataSet的用法小结 TClientDataSet控件继承自TDataSet,其数据存储文件格式扩展名为 .cds,是基于文件型数据存储和操作的控件。该控件封装了对数据进行操作处理的接口和功能,而本身并不依赖上述几种数据库驱动程序,基本上能满足单机"瘦"数据库应用程序的需要。 一、TClientDataSet的基本属性和方法介绍 1、FieldDefs: 字段定义列表属性 开发者可通过单击属性编辑器中该属性编辑按钮,或在该控件上单击右键选择弹出菜单中的"Fields Editor"菜单进行字段编辑。设置完此属性后,实际上就相当于定义了表的结构;如果想装入已有的数据表的结构和数据,可通过单击右键选择弹出菜单中的"Assign Local Data"菜单,从弹出对话框中选取当前窗体中已与数据库连接好的数据集控件名称即可(当前窗体中必须已放置好要套用的数据集控件并打开激活)。 使用注意: 对于自定义的字段名表,该属性编辑完后,该控件仍然无法打开。必须右键单击该控件,选择弹出菜单中的"Create DataSet"菜单,让该控件以上述编辑的字段列表为依据,创建数据集后,才能够被激活打开和使用。否则,会出现类似"ClientDataSet1: Missing data provider or data packet."的错误(包括在运行期,运行期可调用该控件的CreateDataSet方法,从而动态定义字段和表)。 2、FileName属性 说明:数据存储文件的名称。因该控件是基于文件型的数据操作控件,因此,必须指定所操作的数据文件名称(默认扩展名称.cds),从而打开和激活该控件,进而进行数据编辑。 例1:利用此属性打开指定的.cds文件 Delphi代码 var Path:string; begin Path:=ExtractFilePath(Application.ExeName);//取得可执行文件路径 CDataSet1.FileName:=Path+'test.cds'; CDataSet1.Open; end; 3、CreateDataSet方法 说明:该方法以FieldDefs中的字段名表为结构建立数据集,常用来进行动态定义表。 例2:动态创建一具有姓名和年龄两个字段的数据集。 Delphi代码 //创建字段名表 CDataSet.FieldDefs.Clear; withCDataSet.FieldDefs.AddFieldDefdo begin Name:='Name'; Size:=10; DataType:=ftString; end; withCDataSet.FieldDefs.AddFieldDefdo begin Name:='Age'; DataType:=ftInteger; end; //动态创建数据集 CDataSet.CreateDataSet; //激活和打开该数据集 CDataSet.Open; 4、Open方法 说明: 打开和激活数据集控件,从而进行数据编辑。a. 如果指定了FileName属性,则直接用Open方法即可打开和激活该控件,见例1。b. 如果未指定FileName属性,可使用例2方法动态创建和打开数据集,进而操作数据。 5、LoadFromFile和SaveToFile 说明:从文件中装入表结构和数据以及存储数据到文件。该方法类似于Word中的打开新文件和另存为的功能。 例3:将数据集的数据存储到指定文件中 Delphi代码 CDataSet.SaveToFile('C:WindowsHUTest.cds'); 6、First(到首),Prior(向前),Next(向后),Last(到尾),Edit(编辑),CanCel(取消编辑),Post(保存),Insert(插入记录),Append(添加记录),Delete(删除),Refresh(数据刷新)等数据集常用方法。 说明:当指定了FileName属性时,其Post方法可将数据存入指定的文件中,类似其SaveToFile方法;如果未指定存储文件名,则Post方法只将数据存储在RAM中。其它方法,同一般数据集控件使用方法,略。 7、Filter, Filtered: 过滤筛选属性 说明:用于筛选指定条件的记录,用法同一般数据集控件,略。 例4:在已经激活打开的数据集中筛选性别为男性的记录 Delphi代码

【IDEA】idea恢复pom.xml文件显示灰色并带有删除线

通过idea打开spring boot项目后,发现每个服务中的pom.xml文件显示灰色并带有删除线,下面为解决方案 问题截图 解决方案 打开file——settings——build,execution,deployment——Ignored Files,把pom.xml前面的复选框去掉,去掉之后,点击apply和OK 点击OK后,会自动重新加载,如下图

Spring管理bean

场景一 : 一个接口的多实例Bean的选择 首先定义一个接口和两个简单的实现类,并演示一下我们通常的用法 一个输出的接口定义如下 public interface IPrint { void print(String msg); } 对应给以下两个实现 @Service public class ConsolePrint implements IPrint { @Override public void print(String msg) { System.out.println("console print: " + msg); } } @Slf4j @Service public class LogPrint implements IPrint { @Override public void print(String msg) { log.info(“log print: {}”, msg); } } 下面就是我们一般的引用方式 @RestController @RequestMapping(“/api/{edition}/page”) public class MyPageHelperController { @Autowired private HouseMovingService houseMovingService; @Autowired private IPrint print;

delphi 连接轻量级数据库 sqlite3

环境: windows7-64, delphi7, sqlite3 最近搞个小工具,要用到轻量级数据库。以前小型数据库是用mdb的,但连接mdb 需要odbc的支持。 对环境依赖性很大,于是换了一种传说中的轻量级数据库。 sqlite 很小巧,delphi 7 连接sqlite 我用的是 ASQLite 控件。一个ASQLite 控件 和一个 sqlite3.dll 就可以操作 .db 格式的文件, 关于 sqlite3.dll 我发现有多个版本,某些版本delphi7是连接不到的。 这个我也不清楚原因。 先安装ASQLite 控件,安装完后别忘了在Library Path 添加路径。 在工程上新建一个 TDataModule,我们在这里添加数据库连接控件 分别是: TASQLite3DB, TASQLite3Query, TDataSetProvider, TClientDataSet 后两个大家都很熟悉了,设置关联关系也是十分传统 TASQLite3Query 的Connection 关联 TASQLite3DB TDataSetProvider 的 DataSet 关联 TASQLite3Query TClientDataSet 的 ProviderName 关联 TDataSetProvider 至于连接的数据库db文件,这个就交给代码完成,发现若是在属性上指定,会有错误。 try Dir := ExtractFilePath(ParamStr(0)); DBConn.DefaultDir := Dir; DBConn.Database := 'data.db'; DBConn.DriverDLL := Dir + 'sqlite3.dll'; DBConn.Connected := True;

JS中的异步编程与Promise

一、JavaScript的异步编步机制 在了解JavaScript的异步机制之前,我们首先需要理解JavaScript是一种单线程语言。单线程就意味着所有的任务需要按照顺序一次执行,如果前一个任务没有完成,后一个任务就无法开始。这个特性在执行大量或耗时任务时可能会导致阻塞或者界面卡死,这显然是不可取的。 为了解决这个问题,JavaScript引入了异步编程的机制。简单地说,异步就是你现在发出了一个“命令”,但是并不等待这个“命令”完成,而是继续执行下一个“命令”。只有在“听到”之前的那个“命令”完成了的消息时,才会回过头来处理这个“命令”的结果。这就是所谓的异步编程。 二、事件循环(Event Loop)和任务队列(Task Queue) 这种异步的机制是如何实现的呢?关键在于事件循环(Event Loop)和任务队列(Task Queue)。 事件循环是 JavaScript 内部的一个处理过程,系统会在此处不断地循环等待,检查任务队列中是否有任务,如果有,就处理它。 而任务队列,就是一个存储待处理任务的队列,当我们使用 setTimeout、setInterval、ajax等API时,实际上是向任务队列中添加了一个任务。 当主线程空闲时(也就是同步任务都执行完毕),便会去看任务队列里有没有任务,如果有,便将其取出执行;没有的话,则继续等待。 这个模型可以简单地用下面的代码表示: while (true) { let task = taskQueue.pop(); execute(task); } 三、宏任务和微任务 在任务队列中,任务被分为两类:宏任务(MacroTask)和微任务(MicroTask)。两者的区别在于,宏任务在下一轮事件循环开始时执行,微任务在本轮事件循环结束时执行。这意味着微任务的优先级高于宏任务。 常见的宏任务有:script全文(可以看作一种宏任务)、setTimeout、setInterval、setImmediate(Node.js 环境)、I/O、UI渲染。 常见的微任务有:Promise、process.nextTick(Node.js环境)、MutationObserver(html5新特性)。 事件循环的顺序,决定了 JavaScript 代码的执行顺序。过程如下: 执行同步代码,这属于宏任务执行栈为空,查询是否有微任务需要执行执行所有微任务必要的话渲染UI然后开始下一轮 Event loop,执行宏任务中的异步代码 代码示例如下: console.log('script start'); // 宏任务 setTimeout(function() { console.log('setTimeout'); // 宏任务 }, 0); Promise.resolve().then(function() { console.log('promise1'); // 微任务 }).then(function() { console.log('promise2'); // 微任务 }); console.log('script end'); // 宏任务 输出顺序为:script start -> script end -> promise1 -> promise2 -> setTimeout。这是因为JavaScript执行机制决定了微任务比宏任务优先执行。

招聘系统毕业设计(Java+Vue+SpringBoot+MySQL)

博主主页:一季春秋 博主简介:专注Java技术领域和毕业设计项目实战、Java、微信小程序、安卓等技术开发,远程调试部署、代码讲解、文档指导、ppt制作等技术指导。 主要内容:毕业设计(Java项目、小程序、安卓等)、简历模板、学习资料、技术咨询。 精彩专栏推荐订阅👇🏻👇🏻 不然下次找不到哟 SpringBoot+Vue项目持续更新中 http://t.csdn.cn/1mgm8 🍅文末获取联系🍅 目录 一、项目介绍 二、项目主要技术 三、系统功能 3.1 功能模块设计 四、系统实现 4.1 系统前台用户功能实现 4.2 管理员模块实现 4.3 企业模块实现 4.4 用户后台管理模块实现 五、实现代码 5.1 招聘信息关键代码 一、项目介绍 这个系统的设计主要包括方便管理员、企业和用户三者互动的后端数据库,要求系统需要良好的数据处理能力、友好的界面和易用的功能。以mysql为后端数据库,以idea为开发平台,采用springboot架构,建立以个人中心、企业管理、用户管理、岗位类型管理、招聘信息管理、应聘记录管理、留言反馈、系统管理等必要功能的、稳定的招聘系统。 二、项目主要技术 开发语言:Java 使用框架:spring boot 前端技术:JavaScript、Vue 、css3 开发工具:IDEA/MyEclipse/Eclipse、Visual Studio Code 数据库:MySQL 5.7/8.0 数据库管理工具:phpstudy/Navicat JDK版本:jdk1.8 Maven: apache-maven 3.8.1-bin 三、系统功能 本系统结合现今主流管理系统的功能模块以及设计方式进行分析,使用Java语言和Springboot框架进行开发设计,具体研究内容如下: (1)管理员主要对个人中心、企业管理、用户管理、岗位类型管理、招聘信息管理、应聘记录管理、留言反馈、系统管理等功能进行管理。 (2)企业主要对个人中心、岗位类型管理、招聘信息管理、应聘记录管理等功能进行管理。 (3)用户进入系统可以实现对首页、企业、招聘信息、招聘新闻、留言反馈、后台管理、个人中心等进行失踪,还可以进入后台对应聘记录进行管理。 3.1 功能模块设计 招聘系统按照权限的类型进行划分,分为管理员、企业和用户共三个模块。系统实现首页、企业、招聘信息、招聘新闻、留言反馈、后台管理、个人中心等功能进行操作,增强了使用者的操作体验。管理员模块主要针对整个系统的管理进行设计,提高了管理的效率和标准。系统的总体模块设计如下图所示: 四、系统实现 4.1 系统前台用户功能实现 系统首页界面 企业详细页面 招聘信息详细页面 个人中心界面 4.2 管理员模块实现 后台登录界面 企业管理界面 招聘信息管理界面 应聘记录管理界面 系统管理界面 4.3 企业模块实现 企业主界面

veImageX 演进之路:Web 图片加载提速50%

背景说明 火山引擎veImageX演进之路主要介绍了veImageX在字节内部从2012年随着字节成长过程中逐步演进的过程,演进中包括V1、V2、V3版本并最终面向行业输出;整个演进过程中包括服务端、客户端、网络库、业务场景与优化等多个角度介绍在图像处理压缩、省成本与体验优化的经验与方案; 本篇文章重点介绍在web端演进和提供的能力,图片是 Web 站点中的重要元素,图片体积、格式、分辨率以及渲染方式对用户体验有着显著影响。火山引擎veImageX 为业务提供了灵活、高效的一站式图片解决方案和静态素材托管方案,涵盖了上传、存储、处理、分发、评估等图片生产和消费阶段的全部链路。 解决的问题 Web 场景下图片的应用非常广泛,从传统的图文到视频封面都有图片的身影,图片体验是用户体验中很重要的一环,常用于衡量站点性能的 LCP 和 CLS 指标都把图片列为最重要的元素之一。随着业务的发展,用户量增长的同时也带来了 CDN 带宽成本的快速提升,最主要的元素则是图片和视频。因此,方案从体验和成本出发,旨在为用户提升体验的同时降低带宽成本。 用户体验可视化 图片体验问题通常有以下几点: 加载速度慢:图片体积、网络、CDN、处理耗时等因素均会影响加载耗时; 加载失败率高:导致图片加载失败的因素很多,重点在于如何及时定位问题; 渲染体验差:包括图片区域长时间空白、加载后导致页面抖动、出错后无兜底等场景; 开发者往往忽视了图片体验,也不了解图片对站点性能的影响,并且缺少可量化的数据来衡量站点的图片体验。参考 Lighthouse 性能优化指南,方案整合了图片压缩、图片懒加载、图片稳定性布局、错误兜底等能力,并集成了数据监控能力,可结合 火山引擎veImageX 控制台实时大盘数据查看,为业务提供数据上报、数据分析、数据追踪、数据告警等全链路支持。 带宽成本问题 以下问题通常会带来额外的带宽成本: 图片压缩率低; 图片原始分辨率和渲染分辨率不匹配; 采用传统的 PNG、JPEG 等低压缩率格式; 图片未进行懒加载; 除了图片压缩,方案支持了 WebP、AVIF 等高压缩率图片格式的自适应加载和图片分辨率的自适应加载,尽可能减小图片体积。同时集成了图片懒加载,避免不可见区域的图片加载,降低站点 CDN 成本,同时也提升站点整体加载速度。根据内部业务数据,图片传输带宽和图片加载耗时通常可降低 50% 以上。 方案架构 方案总体上可划分为图片加载和数据监控两个部分。 方案架构.png 如图所示,图片加载部分支持分辨率、格式自适应以及懒加载、稳定性布局等特性,其中涉及到图片处理部分基于火山引擎veImageX 服务实现,如图片转码、缩放、压缩等。SDK 侧生成当前环境下最佳的图片格式和分辨率,从服务获取相应的图片 URL,借助云端处理能力在运行时动态生成所需的图片。 数据监控部分可分为加载耗时监控、图片详情监控、画质评估、大图监控、云控配置几部分,监控 SDK 收集相关数据,根据云端下发的配置上报数据,火山引擎veImageX 服务对数据做清洗后可在控制台侧查看数据大盘。 模块详细介绍 图片加载 图片格式自适应 常见的图片格式有 PNG、JPEG、GIF、WebP、AVIF、HEIC 等,其中 WebP、AVIF、HEIC 等高压缩率图片格式可显著减小图片体积。但由于不同浏览器对高压缩率格式的支持情况不同,因此在应用时需要考虑图片加载的环境。三种高压缩率格式在 Web 侧的兼容性如下: WebP AVIF HEIC 在 APP 端,对于不支持的图片格式可采用 SDK 软解的方式进行解码、渲染,Native 侧的性能可保证图片解码的耗时和流量的节省都能有不错的收益。在 Web 侧,由于浏览器性能限制,veImageX 内部性能测试表明,SDK 软解在图片整体耗时方面的收益并不明显,尤其是多图场景下,因此在 Web 侧更适合走格式自适应的方案,即根据浏览器的支持性加载相对最优的图片格式。

Flutter混编方案在起点客户端的实践之路

点击上方蓝字关注我,知识会给你力量 起点读书客户端一直紧跟新技术的潮流,从很早开始,就在进行Flutter的尝试,在筹备了许久之后(移除了包大小的KPI指标),我们终于在最新的业务开发中,使用了Flutter。 Flutter虽然会带来一些包体积的增加,但带来的收益却是: 愉悦的开发体验,不用再忍受漫长的编译,强大的热更新可以快速进行UI开发 跨端的统一UI设计,双端不用做太多的适配就可以运行 开发效率提升一倍以上,同时也提升设计和测试的效率 千呼万唤始出来,让我们来看下起点读书客户端是如何进行Flutter混编开发的。 轻量化引擎架构 由于起点读书客户端目前依然是以原生开发为主,所以我们在嵌入Flutter模块时,首先要考虑的就是使用哪种混合栈方案。目前市面上常见的混合栈方案,主要就是两种:一种是以Flutter Boost为例的单引擎方案,另一种是以EngineGroup来实现的多引擎方案。这两种混合栈的方案,各有一些优缺点。 优势劣势单引擎混合栈与Native独立开来,对Native的依赖最小,混编开发流程清晰、方便混编存在混合栈内存泄漏等问题,会存在一些底层的Crash;Flutter和Native端都需要独立实现一套完整的网络和基础库等基础模块多引擎混合栈相比单引擎方案,性能更好,在多实例下内存压力更小,开发更加简便对Native依赖大,多实例之间数据无法共享,需要从Native进行转发 我们在这两种架构方案的基础上,各取所长,提出了一套轻量化的引擎架构。 首先,我们采用的是EngineGroup的混合栈方案,这个方案对于小规模嵌入Flutter页面的NativeApp来说,是性价比最高的选择,它的技术架构如下所示。 但是和传统的Flutter开发方案又有所不同,我们将Flutter页面当作一个渲染容器,在一个Flutter页面中,所有的数据都来源于Native,Flutter只作渲染UI和处理交互逻辑,这种方案和之前的方案进行对比,结果如下。 优势劣势轻量化引擎方案Flutter端极其轻量,极大化利用Flutter高效开发UI的优势数据依赖Native,存在双向通信,Native需要作一些额外的处理 在这种轻量化的架构方案下,我们作了一些改进: Flutter只作UI渲染,网络请求、基础数据等内容,都通过Native桥接,最大化的复用了Native的已有能力,Flutter端不用重新复刻一套,同时,对于UI上的异常,可以很方便的进行处理,避免在Flutter中使用网络库等能力时带来的新异常 抛弃Flutter端常规的路由概念,将业务页面封装为独立的scheme,类似Native中的ActionUrl,简化调用逻辑 通过搭建一套数据mock的方式,在Flutter端进行开发,避免在开发阶段,需要从Native获取数据的问题 综上所述,经过多方面的考虑和调整,最终确定了当前起点读书Flutter的架构方案。 在当前架构下,Native端需要实现一套通用的Channel协议,通过BasicMessageChannel�来实现一些对性能较高的Channel场景,例如埋点、网络请求等,通过MethodChannel来实现一些通用的Native方法调用,以及拓展业务特有逻辑的方法调用。 参数传递 在创建Flutter页面时,借助dartEntrypointArgs�,可以从Native传递相应的参数,代码如下。 在Flutter端,可以在entry-point�中获取相应的参数。 // XXX主页 @pragma('vm:entry-point') void XXX(List<String>? args) => SafeApp().run(ThemeApp(args: args, child: XXXPage(args))); ❝ 后续继续优化,可以将参数封装为一个Map,双端进行解析,这样在获取参数时能更加具有语义化。 ❞ 桥接 Channel在这个方案中扮演着非常重要的角色,它是Flutter和Native之间的纽带。我们根据Channel的使用场景,将其分为了四类。 NativeCommonApi:适用于与Native频繁通信或者对性能要求较高的场景。 reportException:上报通用异常 reportTrackerImpression:上报页面曝光 reportTrackerClick:上报点击 reportTrackerColumn:上报栏目曝光 doActionUrlCall:执行Native action url NativeFontApi:加载Native字体。 loadNativeFont:加载Native字体 NativeNetApi:加载Native网络请求数据。 getNativeNetBridge:通用get请求 postNativeNetBridge:通用post请求 NativeMethodCall:适用于与Native的单次交互场景,通用的方法需要在这里新增,并在Native中新增实现。 finish:关闭Flutter页面 canPopFlutterPage:是否可以Pop当前Flutter页面(iOS用) isInBookShelf:获取当前bookId是否在书架 getUserGender:获取当前用户Gender showToast:Native显示Toast 对于性能要求较高的场景,我们使用BasicMessageChannel�,而单次的Native调用,我们使用MethodChannel�,经过不同的场景(超大数据量、连续多次频繁请求)等测试,其数据符合预期,调用延时相对于请求时间来说,基本可以忽略不计,同时,其稳定性也经受住了考验。 ❝ 在开发的早期阶段,桥接函数不太丰富的前提下,在开发Flutter时,有时候还是需要Native开发人员对新的通用桥接函数进行补充,但随着函数的丰富,这个操作会越来越少,最后逐渐就不太需要Native开发人员参与Flutter的开发与调试了。 ❞ UI组件化的实践 由于目前起点读书的轻量化引擎架构设计,Flutter只作UI渲染,所以我们需要充分利用Flutter的热更新特性,提高业务UI的开发效率。 黑夜模式与颜色Token 目前起点读书的黑夜模式,有两种设置方式,一种是跟随系统,用户可以在App内部设置,也可以在手机内进行切换,另一种是手动在App内部设置固定黑夜模式或者非黑夜模式。 Flutter页面在创建时,会传入当前App设置黑夜模式的枚举——「system」、「light」、「dark」�,在Flutter中,会根据设置的模式来进行切换。而如果用户在打开Flutter页面后,在手机内进行黑夜模式的切换,Flutter也会自动进行切换。相关代码如下。 在处理颜色的映射时,我们会根据设计给出的映射关系,根据是否为黑夜模式,将指定token映射为对应的色值,例如下面的示例。

网络工程师基础笔记(一)

一、接入网 接入网,是指将端系统物理连接到边缘路由器的网络。 (1)家庭接入:数字用户线(DSL)、电缆、光纤到户(FTTH)卫星和拨号接入。 (2)企业(家庭)接入:以太网、WIFI (3)广域无线接入:3G、LTE 二、物理媒体 导引性媒体:双绞铜线、同轴电缆 非导引性媒体:陆地无线电信道、卫星无线电信道 三、网络核心 网络核心:由互联因特网端系统的链路和交换机组成的网状网络 (1)分组交换 在各种网络应用中,端系统彼此交换报文。它可以执行一种控制功能,也可以包含数据。为了从源端系统向目的端系统发送一个报文,源将长报文划分为较小的数据块,称为分组。而分组通过通信链路和交换机进行传送。且以等于该链路最大传输速率的速度传输通过通信链路。(交换机主要有两类:路由器和链路层交换机) 1.存储转发传输 存储转发指的是,分组交换机在向输出端传送分组的第一个比特之前,首先需要接受到整个分组。 注:关于时延的问题,如果考虑一个一般情况,从源发送一个分组到目的主机,通过N条速率为R组成的路径(有N-1台路由器) 那么,总的传输时延应该=L/R(第一个路由器接受完整个分组)+(N-1)L/R(每个路由器发送分组的时间之和)=N(L/R) 2.排队时延和分组丢失 每台交换机有多个输出链路与之相连,对于每条相连的链路,分组交换机都相应的具有一个输出队列。如果到达的某个分组需要传输的链路正在忙于传输其他分组,那么该分组就必须在输出缓存中等待,这就存在一个排队时延。同时,由于输出队列的大小是有限制的,一旦缓存被充满,就会发生分组丢失的情况。 3.转发表和路由选择协议 在网络核心中,我们提到它是一种网状机构,那么,分组是如何选择路径从源传输到端系统中的呢?在因特网中,每个端系统都有一个IP地址。IP地址具有一种等级结构,每当分组到达一个路由器,路由器就会检查目的IP地址中的一部分,并向一台相邻的路由器转发该分组。(类似于你寄快递,比如江苏省南京市六合区,他就会一级一级的检查并分发下去)。同时,每个路由器都具有一个转发表,用于将目的地址(或目的地址中的一部分)映射成为输出链路。 注:转发表是通过路由选择协议来自动设置的。 (2)电路交换 在电路交换网络中,当端系统通信会话发生时,其为两个端系统建立一条专用的端到端连接。而链路中电路的分配建立,是通过频分复用FDM或时分复用TDM来实现的。 1.FDM在连接期间为每条连接专用一个频段。其中,该频段的宽度称为带宽。 2.而对于一条TDM链路,时间被划分为固定期间的帧,帧划分为固定数量的时隙。当网络跨越链路创建一条连接时,网络在每个帧中为该连接指定一个时隙。 注:对于TDM,一条链路的传输速率等于帧速率*一个时隙中比特的数量。

Kotlin | 在for、forEach循环中正确的使用break、continue

Kotlin 有三种结构化跳转表达式: return:默认从最直接包围它的函数或者匿名函数返回。break:终止最直接包围它的循环。continue:继续下一次最直接包围它的循环。 for循环中使用break、continue for (i in 1..5) { if (i == 3) break //1 这里分别使用break continue return println("i: $i") } println("循环外继续执行") 1处分别使用break、continue、return 替换,执行结果如下: //break i: 1 i: 2 循环外继续执行 //continue i: 1 i: 2 i: 4 i: 5 循环外继续执行 //return i: 1 i: 2 嗯,跟Java中的使用姿势是一样的,继续往下看。 Label标签 在 Kotlin 中任何表达式都可以用标签(label)来标记。 标签的格式为标识符后跟 @ 符号,例如:abc@、loop@都是有效的标签。 要为一个表达式加标签,我们只要在其前加标签即可。示例: loop@ for (i in 1..5){ //... } 这里在嵌套for循环中使用Label,可以控制break及continue的范围: loop@ for (i in 1..2) { println("i: $i"

JS中获取变量参数/$/!$/val/#/选择器符号含义

jQuery 选择器 jQuery 选择器允许您对 HTML 元素组或单个元素进行操作。 jQuery 选择器基于元素的 id、类、类型、属性、属性值等"查找"(或选择)HTML 元素。 它基于已经存在的 CSS 选择器,除此之外,它还有一些自定义的选择器。 jQuery 中所有选择器都以美元符号开头:$()。 元素选择器 Query 元素选择器基于元素名选取元素。 在页面中选取所有 <p> 元素: $("p") 用户点击按钮后,所有 <p> 元素都隐藏: $(document).ready(function(){ $("button").click(function(){ $("p").hide(); }); }); #id 选择器 jQuery #id 选择器通过 HTML 元素的 id 属性选取指定的元素。 页面中元素的 id 应该是唯一的,所以您要在页面中选取唯一的元素需要通过 #id 选择器。 html <input id="cList" type="hidden" value="${couponList}"> 通过 id 选取元素语法如下: var couponStr = $("#cList").val(); .class 选择器 jQuery 类选择器可以通过指定的 class 查找元素。 html <div class="layui-inline"> <a class="layui-btn layui-btn-danger orderAdd_btn" lay-event="

matplotlib如何销毁所有的figure绘图窗口

可以使用 plt.close('all') 命令来销毁所有的figure。这会关闭Matplotlib中所有的图形窗口,包括正在使用的和未使用的。下面是一个例子: import matplotlib.pyplot as plt # 创建两个figure plt.figure() plt.plot([1,2,3]) plt.figure() plt.plot([4,5,6]) # 关闭所有figure plt.close('all') 执行上述代码后,会创建两个图形窗口并在每个窗口中绘制一条曲线。然后调用 plt.close('all') 命令来关闭所有的图形窗口。

matplotlib绘图引起 GUI绘图冲突,QCoreApplication::exec: The event loop is already running 已解决

这个警告通常是因为程序中使用了 QApplication.exec() 或 QGuiApplication.exec() 方法来启动 Qt 的事件循环,然后尝试在 Qt 事件循环运行的同时再次启动事件循环。在本例中,这是因为 plt.show() 本身已经启动了一个事件循环。 解决方案:避免在函数中使用 plt.show() 另一种方法是不在 plot_numpy_array() 函数中使用 plt.show(),而是在调用该函数的地方来控制何时显示图形。 以下是修改后的代码: def plot_numpy_array(data, xlabel=None, ylabel=None, legend=None): x = np.arange(len(data)) fig, ax = plt.subplots() ax.plot(x, data, label=legend) ax.set_xlabel(xlabel) ax.set_ylabel(ylabel) ax.legend() # 不在函数中使用 plt.show(),而是在调用该函数的地方显示图形 return fig # 调用 plot_numpy_array() 函数显示图形 fig = plot_numpy_array(data, xlabel='X Label', ylabel='Y Label', legend='Legend') fig.show()

python将BGR图像转直方图后再滤波示例

可以使用numpy中的convolve函数来实现一维滤波,以下是一个可以指定核大小的函数: import numpy as np def one_dim_filter(arr, kernel_size): if kernel_size % 2 == 0: raise ValueError("Kernel size must be odd") kernel = np.ones(kernel_size) / kernel_size filtered_arr = np.convolve(arr, kernel, mode='same') return filtered_arr 该函数接受两个参数:待滤波的numpy数组和核大小。如果核大小为偶数,则会引发ValueError异常。函数会创建一个大小为kernel_size的均值滤波器,然后将其应用于输入数组arr。最后,使用’mode = same’来确保输出数组与输入数组的大小相同。 对如下的图片三通道的数据拉平后,的直方图数据,进行滤波实验 如下是未进行滤波的数据 以下是滤波后的数据,明显数据变得平滑了许多,这里我是用的是7核 如下是实现计算直方图的函数 def calcHist(channel, levels, histogram_bins, Norm = False): # 将像素值映射到对应的直方图bin上 bins = np.digitize(channel.ravel(), histogram_bins) - 1 # 初始化直方图为0 histogram = np.zeros(len(histogram_bins)-1) # 遍历所有像素,将像素值加入对应的直方图bin for i in range(len(bins)): histogram[bins[i]] += 1 # 将直方图bin中的像素数量归一化到[0, 1]范围 if Norm: histogram /= np.