前端技术
HTML
CSS
Javascript
前端框架和UI库
VUE
ReactJS
AngularJS
JQuery
NodeJS
JSON
Element-UI
Bootstrap
Material UI
服务端和客户端
Java
Python
PHP
Golang
Scala
Kotlin
Groovy
Ruby
Lua
.net
c#
c++
后端WEB和工程框架
SpringBoot
SpringCloud
Struts2
MyBatis
Hibernate
Tornado
Beego
Go-Spring
Go Gin
Go Iris
Dubbo
HessianRPC
Maven
Gradle
数据库
MySQL
Oracle
Mongo
中间件与web容器
Redis
MemCache
Etcd
Cassandra
Kafka
RabbitMQ
RocketMQ
ActiveMQ
Nacos
Consul
Tomcat
Nginx
Netty
大数据技术
Hive
Impala
ClickHouse
DorisDB
Greenplum
PostgreSQL
HBase
Kylin
Hadoop
Apache Pig
ZooKeeper
SeaTunnel
Sqoop
Datax
Flink
Spark
Mahout
数据搜索与日志
ElasticSearch
Apache Lucene
Apache Solr
Kibana
Logstash
数据可视化与OLAP
Apache Atlas
Superset
Saiku
Tesseract
系统与容器
Linux
Shell
Docker
Kubernetes
[单峰函数最小化问题求解 ]的搜索结果
这里是文章列表。热门标签的颜色随机变换,标签颜色没有特殊含义。
点击某个标签可搜索标签相关的文章。
点击某个标签可搜索标签相关的文章。
ElasticSearch
...个让我头疼了好几天的问题——ElasticSearch里的NodeNotActiveException。嘿,我刚接触 Elasticsearch 的时候啊,心里还美滋滋的,心想这东西看着挺easy的,结果嘛……嘿嘿,一不留神就掉坑里了,真是“理想很丰满,现实很骨干”啊!不过还好,经过一番折腾,我终于找到了解决办法。嘿,大家好啊!今天想跟你们聊聊我的故事和一些小感悟,也算是把我踩过的坑、学到的东西分享给大家吧。希望对那些正被同一个问题烦得抓头发的朋友有点用,咱们一起想办法解决它! --- 1. 初识NodeNotActiveException:我的第一次“崩溃” 事情是这样的,我最近在搭建一个基于ElasticSearch的日志分析系统。一切看起来都很顺利,数据导入、索引创建啥的都没问题。但当我尝试对某些节点进行操作时,突然蹦出了这么一行错误: org.elasticsearch.cluster.block.ClusterBlockException: blocked by: [SERVICE_UNAVAILABLE/2/no active shards]; 当时我心里那个急啊!赶紧去查文档,发现这是NodeNotActiveException的表现之一。简单说吧,就好比某个关键的小哥突然“罢工”了,可能是因为它内存不够用,或者网络断了啥的,结果整个团队的工作都乱套了,没法正常运转了。 我当时就纳闷了:“这不是应该自动恢复吗?为啥还要报错呢?”后来才明白,虽然ElasticSearch确实有自我修复机制,但有时候我们需要手动干预才能让它恢复正常。 --- 2. 理解背后的逻辑 为什么会出现这种问题? 在深入了解之前,我觉得有必要先搞清楚这个异常的根本原因。其实NodeNotActiveException并不是什么特别复杂的概念,它主要出现在以下几种情况: - 节点宕机:某个节点由于硬件故障或者网络问题离线了。 - 磁盘空间不足:如果某个节点的磁盘满了,ElasticSearch会自动将其标记为不可用。 - 配置错误:比如分配给节点的资源不够,导致其无法启动。 对于我来说,问题出在第二个点上——磁盘空间不足。我当时为了省钱,给服务器分配的空间少得可怜,结果没多久就发现磁盘直接爆满,把自己都吓了一跳!于是ElasticSearch很生气,直接把该节点踢出了集群。 --- 3. 解决方案一 扩容磁盘空间 既然问题找到了,那就动手解决吧!首先,我决定先扩展磁盘容量。这一步其实很简单,只要登录服务器,增加磁盘大小就行。具体步骤如下: bash 查看当前磁盘状态 df -h 扩展磁盘(假设你已经购买了额外的存储) sudo growpart /dev/xvda 1 sudo resize2fs /dev/xvda1 完成后记得重启ElasticSearch服务: bash sudo systemctl restart elasticsearch 重启之后,神奇的事情发生了——我的节点重新上线了!不过这里有个小技巧分享给大家:如果你不确定扩容是否成功,可以通过以下命令检查磁盘使用情况: bash df -h 看到磁盘空间变大了,心里顿时舒坦了不少。 --- 4. 解决方案二 调整ElasticSearch配置 当然啦,仅仅扩容还不够,还需要优化ElasticSearch的配置文件。特别是那些容易导致内存不足或磁盘占用过高的参数,比如indices.memory.index_buffer_size和indices.store.throttle.max_bytes_per_sec。修改后的配置文件大概长这样: yaml cluster.routing.allocation.disk.threshold_enabled: true cluster.routing.allocation.disk.watermark.low: 85% cluster.routing.allocation.disk.watermark.high: 90% cluster.routing.allocation.disk.watermark.flood_stage: 95% cluster.info.update.interval: 30s 这些设置的意思是告诉ElasticSearch,当磁盘使用率达到85%时开始警告,达到90%时限制写入,超过95%时完全停止操作。这样可以有效避免再次出现类似的问题。 --- 5. 实战演练 代码中的应对策略 除了调整配置,我们还可以通过编写脚本来监控和处理NodeNotActiveException。比如,下面这段Java代码展示了如何捕获异常并记录日志: java import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.indices.CreateIndexRequest; import org.elasticsearch.client.indices.CreateIndexResponse; public class ElasticSearchExample { public static void main(String[] args) { RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(new HttpHost("localhost", 9200, "http"))); try { CreateIndexRequest request = new CreateIndexRequest("test_index"); CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT); System.out.println("Index created: " + response.isAcknowledged()); } catch (Exception e) { if (e instanceof ClusterBlockException) { System.err.println("Cluster block detected: " + e.getMessage()); } else { System.err.println("Unexpected error: " + e.getMessage()); } } finally { try { client.close(); } catch (IOException ex) { System.err.println("Failed to close client: " + ex.getMessage()); } } } } 这段代码的作用是在创建索引时捕获可能发生的异常,并根据异常类型采取不同的处理方式。如果遇到ClusterBlockException,我们可以选择延迟重试或者其他补偿措施。 --- 6. 总结与反思 成长路上的一课 通过这次经历,我深刻体会到,作为一名开发者,不仅要掌握技术细节,还要学会从实际问题出发,找到最优解。NodeNotActiveException这个错误看着不起眼,但其实背后有不少门道呢!比如说,你的服务器硬件是不是有点吃不消了?集群那边有没有啥小毛病没及时发现?还有啊,咱们平时运维的时候是不是也有点松懈了?这些都是得好好琢磨的地方! 最后,我想说的是,技术学习的过程就像爬山一样,有时候会遇到陡峭的山坡,但只要坚持下去,总能看到美丽的风景。希望这篇文章能给大家带来一些启发和帮助!如果还有其他疑问,欢迎随时交流哦~
2025-03-14 15:40:13
64
林中小径
转载文章
...拼接就可以了,现在的问题是如何获取总页数,我一开始的想法是获取分页中“共167页”这个标签后再只保留数字就可以个,但发现运行后获取不到该元素节点,经过排查了解到这个标签是通过js生成的,于是我转换了思路,通过获取最后一个页号来得到一共分了多少页 Document root_doc = Jsoup.connect("http://www.netbian.com/" + kind + "/").get();Elements els = root_doc.select("main .page a");//这里els.eq(els.size() - 2的原因是后边确定按钮用的是a标签要去掉,再去掉一个“下一页”标签Integer page = Integer.parseInt(els.eq(els.size() - 2).text()); 分类页中图片所在的标签结构为: 分类页面下的图片不是我们想要的,我们想要的是点击进去详细页的高清大图,所以需要获取a标签的链接,再从这个链接中获取真正想要的图片。 详细页中图片所在的标签结构为: 二、代码实现 到这里分类页分析的差不多了,我们通过代码来进行获取图片。首先导入Jsoup的jar包:jsoup-1.12.1.jar,如果采用Maven请导入下边的依赖。 <dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.12.1</version></dependency> 在utils创建JsoupPic类,并添加getPic方法,代码如下: public static void getPic(String kind) throws Exception {//get请求方式进行请求Document root_doc = Jsoup.connect("http://www.netbian.com/" + kind + "/").get();//获取分页标签,用于获取总页数Elements els = root_doc.select("main .page a");Integer page = Integer.parseInt(els.eq(els.size() - 2).text());for (int i = 1; i < page; i++) {Document document = null;//这里判断的是当前页号是否为1,如果为1就不拼页号,否则拼上对应的页号if (i == 1) {document = Jsoup.connect("http://www.netbian.com/" + kind + "/index.htm").get();} else {document = Jsoup.connect("http://www.netbian.com/" + kind + "/index_" + i + ".htm").get();}//获取每个分页链接里面a标签的链接,进入链接页面获取当前图拼的大尺寸图片Elements elements = document.select("main .list li a");for (Element element : elements) {String href = element.attr("href");String picUrl = "http://www.netbian.com" + href;Document document1 = Jsoup.connect(picUrl).get();Elements elements1 = document1.select(".endpage .pic p a img");//获取所有图片的链接System.out.println(elements1);} }} 在分类页中有一个隐藏的问题图片: 正常的图片链接都是以“/”开头,以“.htm”结尾,而每个分类下的第三张图片的链接都是“http://pic.netbian.com/”,如果不过滤的话会报如下错误: 所以这里必须要判断一下: Elements elements = document.select("main .list li a");for (Element element : elements) {String href = element.attr("href");//判断是否是以“/”开头if (href.startsWith("/")) {String picUrl = "http://www.netbian.com" + href;Document document1 = Jsoup.connect(picUrl).get();Elements elements1 = document1.select(".endpage .pic p a img");System.out.println(elements1);} } 到这里,页面就已经分析好了,问题基本上已经解决了,接下来我们需要将图片存到我们的系统里,这里我将图片保存到我的电脑桌面上,并按照分类来存储图片。 首先是要获取桌面路径,在utils包下创建Download类,添加getDesktop方法,代码如下: public static File getDesktop(){FileSystemView fsv = FileSystemView.getFileSystemView();File path=fsv.getHomeDirectory(); return path;} 接着我们再该类中添加下载图片的方法: //urlPath为网络图片的路径,savePath为要保存的本地路径(这里指定为桌面下的images文件夹)public static void download(String urlPath,String savePath) throws Exception {// 构造URLURL url = new URL(urlPath);// 打开连接URLConnection con = url.openConnection();//设置请求超时为5scon.setConnectTimeout(51000);// 输入流InputStream is = con.getInputStream();// 1K的数据缓冲byte[] bs = new byte[1024];// 读取到的数据长度int len;// 输出的文件流File sf=new File(savePath);int randomNo=(int)(Math.random()1000000);String filename=urlPath.substring(urlPath.lastIndexOf("/")+1,urlPath.length());//获取服务器上图片的名称filename=new java.text.SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date())+randomNo+filename;//时间+随机数防止重复OutputStream os = new FileOutputStream(sf.getPath()+"\\"+filename);// 开始读取while ((len = is.read(bs)) != -1) {os.write(bs, 0, len);}// 完毕,关闭所有链接os.close();is.close();} 写好后,我们再完善一下JsouPic中的getPic方法。 public static void getPic(String kind) throws Exception {//get请求方式进行请求Document root_doc = Jsoup.connect("http://www.netbian.com/" + kind + "/").get();//获取分页标签,用于获取总页数Elements els = root_doc.select("main .page a");Integer page = Integer.parseInt(els.eq(els.size() - 2).text());for (int i = 1; i < page; i++) {Document document = null;//这里判断的是当前页号是否为1,如果为1就不拼页号,否则拼上对应的页号if (i == 1) {document = Jsoup.connect("http://www.netbian.com/" + kind + "/index.htm").get();} else {document = Jsoup.connect("http://www.netbian.com/" + kind + "/index_" + i + ".htm").get();}File desktop = Download.getDesktop();Download.checkPath(desktop.getPath() + "\\images\\" + kind);//获取每个分页链接里面a标签的链接,进入链接页面获取当前图拼的大尺寸图片Elements elements = document.select("main .list li a");for (Element element : elements) {String href = element.attr("href");if (href.startsWith("/")) {String picUrl = "http://www.netbian.com" + href;Document document1 = Jsoup.connect(picUrl).get();Elements elements1 = document1.select(".endpage .pic p a img");Download.download(elements1.attr("src"), desktop.getPath() + "\\images\\" + kind);} }} } 在Download类中,我添加了checkPath方法,用于判断目录是否存在,不存在就创建一个。 public static void checkPath(String savePath) throws Exception {File file = new File(savePath);if (!file.exists()){file.mkdirs();} } 最后在mainapp包内创建PullPic类,并添加主方法。 package com.asahi.mainapp;import com.asahi.common.Kind;import com.asahi.common.PrintLog;import com.asahi.utils.JsoupPic;import java.util.Scanner;public class PullPic {public static void main(String[] args) throws Exception {new PullPic().downloadPic();}public void downloadPic() throws Exception {System.out.println("启动程序>>\n请输入所爬取的分类:");Scanner scanner = new Scanner(System.in);String kind = scanner.next();while(!Kind.contains(kind)){System.out.println("分类不存在,请重新输入:");kind = scanner.next();}System.out.println("分类输入正确!");System.out.println("开始下载>>");JsoupPic.getPic(kind);} } 三、成果展示 最终的运行结果如下: 最终的代码已上传到我的github中,点击“我的github”进行查看。 在学习Java爬虫的过程中,我收获了很多,一开始做的时候确实遇到了很多困难,这次写的获取图片也是最基础的,还可以继续深入。本来我想写一个通过多线程来获取图片来着,也尝试着去写了一下,越写越跑偏,暂时先放着不处理吧,等以后有时间再来弄,我想问题应该不大,只是考虑的东西有很多。希望大家多多指点不足,有哪些需要改进的地方,我也好多学习学习๑乛◡乛๑。 本篇文章为转载内容。原文链接:https://blog.csdn.net/qq_39693281/article/details/108463868。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-06-12 10:26:04
130
转载
转载文章
...HR) 没什么过多的问题,主要就是聊了一下自己今后的职业规划,告知了薪资组成体系等等。 插播一条福利!!!最近整理了一套1000道面试题的文档(详细内容见文首推荐文章),以及大厂面试真题,和最近看的几本书。 需要刷题和跳槽的朋友,这些可以免费赠送给大家,帮忙转发文章,宣传一下,后台私信【面试】免费领取! 小天:好像问了两次看书的情况诶?现在面试还问这个? 程序员H:是啊,幸亏之前为了弄懂JVM还看了两本书,不然真不知道说啥了! 小天:看来,我也要找几本书去看了,感情没看过两本书都不敢跳槽了! 程序员H:对了,还有简历,告诉你一个捷径 简历尽量写好一些,项目经验突出: 1、自己的知识广度和深度 2、自身的优势 3、项目的复杂性和难度以及指标 4、自己对于项目做的贡献或者优化 程序员H:唉~这还不能走可怎么办呀!你说,我把主管打一顿,是不是马上就可以走了? 小天:... 查看全文 http://www.taodudu.cc/news/show-3387369.html 相关文章: 阿里菜鸟面经 Java后端开发 社招三年 已拿offer 阿里 菜鸟网络(一面) 2021年阿里菜鸟网络春招实习岗面试分享,简历+面试+面经全套资料! 阿里菜鸟国际Java研发面经(三面+总结):JVM+架构+MySQL+Redis等 2021年3月29日 阿里菜鸟实习面试(一面)(含部分总结) mongodb 子文档排序_猫鼬101:基础知识,子文档和人口简介 特征工程 计算方法Gauss-Jordan消去法求线性方程组的解 使用(VAE)生成建模,理解可变自动编码器背后的数学原理 视觉SLAM入门 -- 学习笔记 - Part2 带你入门nodejs第一天——node基础语法及使用 python3数据结构_Python3-数据结构 debezium-connect-oracle使用 相关数值分析多种算法代码 android iphone treeview,Android之IphoneTreeView带组指示器的ExpandableListView效果 nginx rewrite功能使用 3-3 OneHot编码 JavaWeb:shiro入门小案例 MySQL的定义、操作、控制、查询语言的用法 MongoDB入门学习(三):MongoDB的增删查改 赋值、浅复制和深复制解析 以及get/set应用 他是吴恩达导师,被马云聘为「达摩院」首座 Jordan 标准型定理 列主元的Gauss-Jordan消元法-python实现 Jordan 块的几何 若尔当型(The Jordan form) 第七章 其他神经网络类型 解决迁移系统后无法配置启用WindowsRE环境的问题 宝塔面板迁移系统盘/www到数据盘/home 使用vmware vconverter从物理机迁移系统到虚拟机P2V 本篇文章为转载内容。原文链接:https://blog.csdn.net/m0_62695120/article/details/124510157。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-03-08 20:01:49
68
转载
转载文章
...,及时发现并解决潜在问题,这对于构建高性能、高可用的分布式数据库架构具有重要意义。 综上所述,紧跟数据库技术发展潮流,关注MariaDB等开源数据库软件的更新动态,探索云端数据库运维实践与高可用性设计,无疑将助力企业在数字化转型过程中更好地利用数据库这一关键基础设施,以支撑更加复杂多变的业务场景需求。
2023-07-12 10:11:01
310
转载
转载文章
...复杂逻辑的存储过程、函数、触发器等数据库对象。在文章中,使用PL/SQL执行了一系列对Oracle AQ的操作,如创建队列、启动队列、入队和出队消息等。 JDBC连接参数类 , Java Database Connectivity (JDBC) 连接参数类是Java程序中用于存储数据库连接信息的类。在文中提到的JmsConfig类中,包含了诸如用户名、密码、数据库URL以及目标队列名称等连接参数,这些参数被用于初始化和管理到Oracle数据库的JDBC连接,以便Java应用程序能够与Oracle AQ进行交互。 CustomDatumFactory与CustomDatum , 在Java与Oracle数据库类型转换过程中,CustomDatumFactory和CustomDatum是Oracle JDBC驱动提供的接口和类,用于将Oracle数据库的自定义数据类型(如在本例中的demo_queue_payload_type)转换为Java对象,以便在Java应用程序中处理。CustomDatumFactory负责创建和解析CustomDatum对象,而CustomDatum则表示一个可定制的数据结构,可以与数据库中的自定义数据类型相对应。
2023-12-17 14:22:22
138
转载
转载文章
...因空指针异常而导致的问题。 EasyExcel , EasyExcel是阿里巴巴开源的一个Java处理Excel工具,专注于让Excel数据处理变得简单、快速且占用内存低。通过使用EasyExcel,开发者可以轻松实现Excel文件的读写操作,支持大文件流式读写、自定义样式和模板填充等功能,并提供了丰富的API及回调接口以满足复杂场景下的表格数据处理需求。 MybatisPlus , MybatisPlus是在Mybatis的基础上进行扩展的一套持久层框架,它提供了丰富的增强功能,例如单表基本的CRUD操作、分页查询、性能分析插件以及动态表名、自动填充字段等特性。MybatisPlus简化了开发人员对数据库的操作,降低了SQL编写的工作量,尤其在处理简单的单表操作时,极大地提升了开发效率和代码可读性。 JSON , JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。在文中提到的Fastjson是一个Java语言编写的高性能功能完备的JSON库,它可以将Java对象转换成JSON字符串,也可以将JSON字符串反序列化成Java对象,广泛应用于Web服务与前后端数据交互、配置文件存储、日志记录等多种场景。 IPage , IPage是MybatisPlus中封装的分页对象,用来进行数据分页查询。它包含了当前页码、每页显示条数以及总记录数等信息。在执行SQL查询时,MybatisPlus会根据IPage对象的内容自动拼接SQL分页语句,从而实现了数据的高效分页加载,减轻了数据库压力并优化了应用程序性能。
2023-05-26 23:30:52
268
转载
转载文章
...上传早已不是什么新鲜问题,在.net 2.0时代,HTML5也还没有问世,要实现这样的功能,要么是改web.config,要么是用flash,要么是用一些第三方控件,然而这些解决问题的方法要么很麻烦,比如改配置,要么不稳定,比如文件上G以后,上传要么死掉,要么卡住,通过设置web.config并不能很好的解决这些问题。 这是一个Html5统治浏览器的时代,在这个新的时代,这种问题已被简化并解决,我们可以利用Html5分片上传的技术,那么Plupload则是一个对此技术进行封装的前端脚本库,这个库的好处是可以自动检测浏览器是否支持html5技术,不支持再检测是否支持flash技术,甚至是sliverlight技术,如果支持,就使用检测到的技术。 那么这个库到哪里下载,怎么搭建呢,比较懒的童鞋还是用Install-Package Plupload搞定吧,一个命令搞定所有事 Plupload支持的功能这里就不细说了,什么批量上传,这里我没有用到,主要是感觉它支持的事件非常丰富,文件选取后的事件,文件上传中的事件(可获得文件的上传进度),文件上传成功的事件,文件上传失败的事件,等等 我的例子主要是上传一个单个文件,并显示上传的进度条(使用jQuery的一个进度条插件) 下面的例子主要是为文件上传交给 UploadCoursePackage.ashx 来处理 /ProgressBar/ var progressBar = $("loading").progressbar({ width: '500px', color: 'B3240E', border: '1px solid 000000' }); /Plupload/ //实例化一个plupload上传对象 var uploader = new plupload.Uploader({ browse_button: 'browse', //触发文件选择对话框的按钮,为那个元素id runtimes: 'html5,flash,silverlight,html4',//兼容的上传方式 url: "Handlers/UploadCoursePackage.ashx", //后端交互处理地址 max_retries: 3, //允许重试次数 chunk_size: '10mb', //分块大小 rename: true, //重命名 dragdrop: false, //允许拖拽文件进行上传 unique_names: true, //文件名称唯一性 filters: { //过滤器 max_file_size: '999999999mb', //文件最大尺寸 mime_types: [ //允许上传的文件类型 { title: "Zip", extensions: "zip" }, { title: "PE", extensions: "pe" } ] }, //自定义参数 (键值对形式) 此处可以定义参数 multipart_params: { type: "misoft" }, // FLASH的配置 flash_swf_url: "../Scripts/plupload/Moxie.swf", // Silverligh的配置 silverlight_xap_url: "../Scripts/plupload/Moxie.xap", multi_selection: false //true:ctrl多文件上传, false 单文件上传 }); //在实例对象上调用init()方法进行初始化 uploader.init(); uploader.bind('FilesAdded', function (uploader, files) { $("<%=fileSource.ClientID %>").val(files[0].name); $.ajax( { type: 'post', url: 'HardDiskSpace.aspx/GetHardDiskFreeSpace', data: {}, dataType: 'json', contentType: 'application/json;charset=utf-8', success: function (result) { //选择文件以后检测服务器剩余磁盘空间是否够用 if (files.length > 0) { if (parseInt(files[0].size) > parseInt(result.d)) { $('error-msg').text("文件容量大于剩余磁盘空间,请联系管理员!"); } else { $('error-msg').text(""); } } }, error: function (xhr, err, obj) { $('error-msg').text("检测服务器剩余磁盘空间失败"); } }); }); uploader.bind('UploadProgress', function (uploader, file) { var percent = file.percent; progressBar.progress(percent); }); uploader.bind('FileUploaded', function (up, file, callBack) { var data = $.parseJSON(callBack.response); if (data.statusCode === "1") { $("<%=hfPackagePath.ClientID %>").val(data.filePath); var id = $("<%=hfCourseID.ClientID %>").val(); __doPostBack("save", id); } else { hideLoading(); $('error-msg').text(data.message); } }); uploader.bind('Error', function (up, err) { alert("文件上传失败,错误信息: " + err.message); }); /Plupload/ 后台 UploadCoursePackage.ashx 的代码也重要,主要是文件分片跟不分片的处理方式不一样 using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.IO; namespace WebUI.Handlers { /// <summary> /// UploadCoursePackage 的摘要说明 /// </summary> public class UploadCoursePackage : IHttpHandler { public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/plain"; int statuscode = 1; string message = string.Empty; string filepath = string.Empty; if (context.Request.Files.Count > 0) { try { string resourceDirectoryName = System.Configuration.ConfigurationManager.AppSettings["resourceDirectory"]; string path = context.Server.MapPath("~/" + resourceDirectoryName); if (!Directory.Exists(path)) Directory.CreateDirectory(path); int chunk = context.Request.Params["chunk"] != null ? int.Parse(context.Request.Params["chunk"]) : 0; //获取当前的块ID,如果不是分块上传的。chunk则为0 string fileName = context.Request.Params["name"]; //这里写的比较潦草。判断文件名是否为空。 string type = context.Request.Params["type"]; //在前面JS中不是定义了自定义参数multipart_params的值么。其中有个值是type:"misoft",此处就可以获取到这个值了。获取到的type="misoft"; string ext = Path.GetExtension(fileName); //fileName = string.Format("{0}{1}", Guid.NewGuid().ToString(), ext); filepath = resourceDirectoryName + "/" + fileName; fileName = Path.Combine(path, fileName); //对文件流进行存储 需要注意的是 files目录必须存在(此处可以做个判断) 根据上面的chunk来判断是块上传还是普通上传 上传方式不一样 ,导致的保存方式也会不一样 FileStream fs = new FileStream(fileName, chunk == 0 ? FileMode.OpenOrCreate : FileMode.Append); //write our input stream to a buffer Byte[] buffer = null; if (context.Request.ContentType == "application/octet-stream" && context.Request.ContentLength > 0) { buffer = new Byte[context.Request.InputStream.Length]; context.Request.InputStream.Read(buffer, 0, buffer.Length); } else if (context.Request.ContentType.Contains("multipart/form-data") && context.Request.Files.Count > 0 && context.Request.Files[0].ContentLength > 0) { buffer = new Byte[context.Request.Files[0].InputStream.Length]; context.Request.Files[0].InputStream.Read(buffer, 0, buffer.Length); } //write the buffer to a file. if (buffer != null) fs.Write(buffer, 0, buffer.Length); fs.Close(); statuscode = 1; message = "上传成功"; } catch (Exception ex) { statuscode = -1001; message = "保存时发生错误,请确保文件有效且格式正确"; Util.LogHelper logger = new Util.LogHelper(); string path = context.Server.MapPath("~/Logs"); logger.WriteLog(ex.Message, path); } } else { statuscode = -404; message = "上传失败,未接收到资源文件"; } string msg = "{\"statusCode\":\"" + statuscode + "\",\"message\":\"" + message + "\",\"filePath\":\"" + filepath + "\"}"; context.Response.Write(msg); } public bool IsReusable { get { return false; } } } } 再附送一个检测服务器端硬盘剩余空间的功能吧 using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Web; using System.Web.Script.Services; using System.Web.Services; using System.Web.UI; using System.Web.UI.WebControls; namespace WebUI { public partial class CheckHardDiskFreeSpace : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } /// <summary> /// 获取磁盘剩余容量 /// </summary> /// <returns></returns> [WebMethod] public static string GetHardDiskFreeSpace() { const string strHardDiskName = @"F:\"; var freeSpace = string.Empty; var drives = DriveInfo.GetDrives(); var myDrive = (from drive in drives where drive.Name == strHardDiskName select drive).FirstOrDefault(); if (myDrive != null) { freeSpace = myDrive.TotalFreeSpace+""; } return freeSpace; } } } 效果展示: 详细配置信息可以参考这篇文章:http://blog.ncmem.com/wordpress/2019/08/12/plupload%e4%b8%8a%e4%bc%a0%e6%95%b4%e4%b8%aa%e6%96%87%e4%bb%b6%e5%a4%b9-2/ 本篇文章为转载内容。原文链接:https://blog.csdn.net/weixin_45525177/article/details/100654639。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-12-19 09:43:46
127
转载
Ruby
...得很慢,我以为是硬件问题,结果发现是自己在并发编程上犯了错。嘿,今天咱们就来聊聊那些经常犯的小错吧!我呢,打算用一些接地气的例子,跟大家伙儿一起看看这些错误长啥样,顺便学学怎么躲开它们。毕竟谁也不想踩雷不是? --- 2. 什么是并发编程? 简单来说,并发编程就是让程序在同一时间执行多个任务。在Ruby中,我们可以用线程(Thread)来实现这一点。比如说啊,你正在倒腾一堆数据的时候,完全可以把它切成一小块一小块的,然后让每个线程去负责一块,这样一来,效率直接拉满,干活儿的速度蹭蹭往上涨! 但是,问题来了:并发编程虽然强大,但它并不是万能药。哎呀,经常会有这样的情况呢——自个儿辛辛苦苦改代码,还以为是在让程序变得更好,结果一不小心,又给它整出了新麻烦,真是“好心办坏事”的典型啊!接下来,我们来看几个具体的例子。 --- 3. 示例一 共享状态的混乱 场景描述: 假设你正在开发一个电商网站,需要统计用户的购买记录。你琢磨着干脆让多线程上阵,给这个任务提速,于是打算让每个线程各管一拨用户的活儿,分头行动效率肯定更高!看起来很合理对不对? 问题出现: 问题是,当你让多个线程共享同一个变量(比如一个全局计数器),事情就开始变得不可控了。Ruby 的线程可不是完全分开的,这就有点像几个人共用一个记事本,大家都能随便写东西上去。结果就是,这本子可能一会儿被这个写点,一会儿被那个划掉,最后你都不知道上面到底写了啥,数据就乱套了。 代码示例: ruby 错误的代码 counter = 0 threads = [] 5.times do |i| threads << Thread.new do 100_000.times { counter += 1 } end end threads.each(&:join) puts "Counter: {counter}" 分析: 这段代码看起来没什么问题,每个线程都只是简单地增加计数器。但实际情况却是,输出的结果经常不是期望的500_000,而是各种奇怪的数字。这就好比说,counter += 1 其实不是一步到位的简单操作,它得先“读一下当前的值”,再“给这个值加1”,最后再“把新的值存回去”。问题是,在这中间的每一个小动作,都可能被别的线程突然插队过来捣乱! 解决方案: 为了避免这种混乱,我们需要使用线程安全的操作,比如Mutex(互斥锁)。Mutex可以确保每次只有一个线程能够修改某个变量。 修正后的代码: ruby 正确的代码 require 'thread' counter = 0 mutex = Mutex.new threads = [] 5.times do |i| threads << Thread.new do 100_000.times do mutex.synchronize { counter += 1 } end end end threads.each(&:join) puts "Counter: {counter}" 总结: 这一段代码告诉我们,共享状态是一个雷区。如果你非要用共享变量,记得给它加上锁,不然后果不堪设想。 --- 4. 示例二 死锁的诅咒 场景描述: 有时候,我们会遇到更复杂的情况,比如两个线程互相等待对方释放资源。哎呀,这种情况就叫“死锁”,简直就像两只小猫抢一个玩具,谁都不肯让步,结果大家都卡在那里动弹不得,程序也就这样傻乎乎地停在原地,啥也干不了啦! 问题出现: 想象一下,你有两个线程,A线程需要获取锁X,B线程需要获取锁Y。想象一下,A和B两个人都想打开两把锁——A拿到了锁X,B拿到了锁Y。然后呢,A心想:“我得等B先把他的锁Y打开,我才能继续。”而B也在想:“等A先把她的锁X打开,我才能接着弄。”结果俩人就这么干等着,谁也不肯先放手,最后就成了“死锁”——就像两个人在拔河,谁都不松手,僵在那里啥也干不成。 代码示例: ruby 死锁的代码 lock_a = Mutex.new lock_b = Mutex.new thread_a = Thread.new do lock_a.synchronize do puts "Thread A acquired lock A" sleep(1) lock_b.synchronize do puts "Thread A acquired lock B" end end end thread_b = Thread.new do lock_b.synchronize do puts "Thread B acquired lock B" sleep(1) lock_a.synchronize do puts "Thread B acquired lock A" end end end thread_a.join thread_b.join 分析: 在这段代码中,两个线程都在尝试获取两个不同的锁,但由于它们的顺序不同,最终导致了死锁。运行这段代码时,你会发现程序卡住了,没有任何输出。 解决方案: 为了避免死锁,我们需要遵循“总是按照相同的顺序获取锁”的原则。比如,在上面的例子中,我们可以强制让所有线程都先获取锁A,再获取锁B。 修正后的代码: ruby 避免死锁的代码 lock_a = Mutex.new lock_b = Mutex.new thread_a = Thread.new do [lock_a, lock_b].each do |lock| lock.synchronize do puts "Thread A acquired lock {lock.object_id}" end end end thread_b = Thread.new do [lock_a, lock_b].each do |lock| lock.synchronize do puts "Thread B acquired lock {lock.object_id}" end end end thread_a.join thread_b.join 总结: 死锁就像一只隐形的手,随时可能掐住你的喉咙。记住,保持一致的锁顺序是关键! --- 5. 示例三 不恰当的线程池 场景描述: 线程池是一种管理线程的方式,它可以复用线程,减少频繁创建和销毁线程的开销。但在实际使用中,很多人会因为配置不当而导致性能下降甚至崩溃。 问题出现: 假设你创建了一个线程池,但线程池的大小设置得不合理。哎呀,这就好比做饭时锅不够大,菜都堆在那儿煮不熟,菜要是放太多呢,锅又会冒烟、潽得到处都是,最后饭也没做好。线程池也一样,太小了任务堆成山,程序半天没反应;太大了吧,电脑资源直接被榨干,啥事也干不成,还得收拾烂摊子! 代码示例: ruby 线程池的错误用法 require 'thread' pool = Concurrent::FixedThreadPool.new(2) 20.times do |i| pool.post do sleep(1) puts "Task {i} completed" end end pool.shutdown pool.wait_for_termination 分析: 在这个例子中,线程池的大小被设置为2,但有20个任务需要执行。哎呀,这就好比你请了个帮手,但他一次只能干两件事,其他事儿就得排队等着,得等前面那两件事儿干完了,才能轮到下一件呢!这种情况下,整个程序的执行时间会显著延长。 解决方案: 为了优化线程池的性能,我们需要根据系统的负载情况动态调整线程池的大小。可以使用Concurrent::CachedThreadPool,它会根据当前的任务数量自动调整线程的数量。 修正后的代码: ruby 使用缓存线程池 require 'concurrent' pool = Concurrent::CachedThreadPool.new 20.times do |i| pool.post do sleep(1) puts "Task {i} completed" end end sleep(10) 给线程池足够的时间完成任务 pool.shutdown pool.wait_for_termination 总结: 线程池就像一把双刃剑,用得好可以提升效率,用不好则会成为负担。记住,线程池的大小要根据实际情况灵活调整。 --- 6. 示例四 忽略异常的代价 场景描述: 并发编程的一个常见问题是,线程中的异常不容易被察觉。如果你没有妥善处理这些异常,程序可能会因为一个小错误而崩溃。 问题出现: 假设你有一个线程在执行某个操作时抛出了异常,但你没有捕获它,那么整个线程池可能会因此停止工作。 代码示例: ruby 忽略异常的代码 threads = [] 5.times do |i| threads << Thread.new do raise "Error in thread {i}" if i == 2 puts "Thread {i} completed" end end threads.each(&:join) 分析: 在这个例子中,当i == 2时,线程会抛出一个异常。哎呀糟糕!因为我们没抓住这个异常,程序直接就挂掉了,别的线程啥的也别想再跑了。 解决方案: 为了防止这种情况发生,我们应该在每个线程中添加异常捕获机制。比如,可以用begin-rescue-end结构来捕获异常并进行处理。 修正后的代码: ruby 捕获异常的代码 threads = [] 5.times do |i| threads << Thread.new do begin raise "Error in thread {i}" if i == 2 puts "Thread {i} completed" rescue => e puts "Thread {i} encountered an error: {e.message}" end end end threads.each(&:join) 总结: 异常就像隐藏在暗处的敌人,稍不注意就会让你措手不及。学会捕获和处理异常,是成为一个优秀的并发编程者的关键。 --- 7. 结语 好了,今天的分享就到这里啦!并发编程确实是一项强大的技能,但也需要谨慎对待。大家看看今天这个例子,是不是觉得有点隐患啊?希望能引起大家的注意,也学着怎么避开这些坑,别踩雷了! 最后,我想说的是,编程是一门艺术,也是一场冒险。每次遇到新挑战,我都觉得像打开一个神秘的盲盒,既兴奋又紧张。不过呢,光有好奇心还不够,还得有点儿耐心,就像种花一样,得一点点浇水施肥,不能急着看结果。相信只要我们不断学习、不断反思,就一定能写出更加优雅、高效的代码! 祝大家编码愉快!
2025-04-25 16:14:17
32
凌波微步
Spark
...分布式缓存操作时出现问题 一、问题初现 分布式缓存的初衷与现状 嘿,朋友们!今天我们来聊聊Spark在分布式缓存操作中遇到的一些坑。说到Spark,它可是大数据处理界的明星选手,性能强大,功能丰富。但即使是这么优秀的框架,有时候也会让我们头疼不已。 分布式缓存是Spark的一个重要特性,它的核心目标是减少重复计算,提升任务执行效率。简单来说,就是把一些频繁使用的数据放到内存里,供多个任务共享。听起来是不是很美好?但实际上,我在实际开发过程中遇到了不少麻烦。 比如有一次,我正在做一个数据分析项目,需要多次对同一份数据进行操作。我寻思着,这不就是常规操作嘛,直接用Spark的分布式缓存功能得了,这样岂不是能省掉好多重复加载的麻烦?嘿,事情是这样的——我辛辛苦苦搞完了任务,满怀期待地提交上去,结果发现这运行速度简直让人无语,不仅没达到预期的飞快效果,反而比啥缓存都不用的时候还慢!当时我就蒙圈了,心里直嘀咕:“卧槽,这是什么神仙操作?”没办法,只能硬着头皮一点点去查问题,最后才慢慢搞清楚了分布式缓存里到底藏着啥猫腻。 二、深入分析 为什么缓存反而变慢? 经过一番折腾,我发现问题出在以下几个方面: 2.1 数据量太大导致内存不足 首先,大家要明白一点,Spark的分布式缓存本质上是将数据存储在集群节点的内存中。要是数据量太大,超出了单个节点能装下的内存容量,那就会把多余的数据写到磁盘上,这个过程叫“磁盘溢写”。但这样一来,任务的速度就会被拖慢,变得特别磨叽。 举个例子吧,假设你有一份1GB大小的数据集,而你的集群节点只有512MB的可用内存。你要是想把这份数据缓存起来,Spark会自己挑个序列化的方式给数据“打包”,顺便还能压一压体积。不过呢,就算是这样,还是有可能会出现溢写这种烦人的情况,挡都挡不住。唉,真是没想到啊,本来想靠着缓存省事儿提速呢,结果这操作反倒因为磁盘老是读写(频繁I/O)变得更卡了,简直跟开反向加速器似的! 解决办法也很简单——要么增加节点的内存配置,要么减少需要缓存的数据规模。当然,这需要根据实际情况权衡利弊。 2.2 序列化方式的选择不当 另一个容易被忽视的问题是序列化方式的选择。Spark提供了多种序列化机制,包括JavaSerializer、KryoSerializer等。不同的序列化方式会影响数据的大小以及读取效率。 我曾经试过直接使用默认的JavaSerializer,结果发现性能非常差。后来改用了KryoSerializer之后,才明显感觉到速度有所提升。话说回来啊,用 KryoSerializer 的时候可别忘了先给所有要序列化的类都注册好,不然程序很可能就“翻车”报错啦! java import org.apache.spark.serializer.KryoRegistrator; import com.esotericsoftware.kryo.Kryo; public class MyRegistrator implements KryoRegistrator { @Override public void registerClasses(Kryo kryo) { kryo.register(MyClass.class); // 注册其他需要序列化的类... } } 然后在SparkConf中设置: java SparkConf conf = new SparkConf(); conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer"); conf.set("spark.kryo.registrator", "MyRegistrator"); 2.3 缓存时机的选择失误 还有一个关键点在于缓存的时机。有些人一启动任务就赶紧给数据加上.cache(),觉得这样数据就能一直乖乖待在内存里,不用再费劲去读了。但实际上,这种做法并不总是最优解。 比如,在某些情况下,数据可能只会在特定阶段被频繁访问,而在其他阶段则很少用到。要是你提前把这部分数据缓存了,不光白白占用了宝贵的内存空间,搞不好后面真要用缓存的地方还找不到足够的空位呢! 因此,合理规划缓存策略非常重要。比如说,在某个任务快开始了,你再随手调用一下.cache()这个方法,这样就能保证数据乖乖地待在内存里,别到时候卡壳啦! 三、实践案例 如何正确使用分布式缓存? 接下来,我想分享几个具体的案例,帮助大家更好地理解和运用分布式缓存。 案例1:简单的词频统计 假设我们有一个文本文件,里面包含了大量的英文单词。我们的目标是统计每个单词出现的次数。为了提高效率,我们可以先将文件内容缓存起来,然后再进行处理。 scala val textFile = sc.textFile("hdfs://path/to/input.txt") textFile.cache() val wordCounts = textFile.flatMap(_.split(" ")) .map(word => (word, 1)) .reduceByKey(_ + _) wordCounts.collect().foreach(println) 在这个例子中,.cache()方法确保了textFile RDD的内容只被加载一次,并且可以被后续的操作共享。其实嘛,要是没用缓存的话,每次你调用flatMap或者map的时候,都得重新去原始数据里翻一遍,这就跟每次出门都得把家里所有东西再检查一遍似的,纯属给自己找麻烦啊! 案例2:多步骤处理流程 有时候,一个任务可能会涉及到多个阶段的处理,比如过滤、映射、聚合等等。在这种情况下,合理安排缓存的位置尤为重要。 python from pyspark.sql import SparkSession spark = SparkSession.builder.appName("WordCount").getOrCreate() df = spark.read.text("hdfs://path/to/input.txt") 第一步:将文本拆分为单词 words = df.selectExpr("split(value, ' ') as words").select("words.") 第二步:缓存中间结果 words.cache() 第三步:统计每个单词的出现次数 word_counts = words.groupBy("value").count() word_counts.show() 这里,我们在第一步处理完之后立即调用了.cache()方法,目的是为了保留中间结果,方便后续步骤复用。要是不这么干啊,那每走一步都得把上一步的算一遍,想想就费劲,效率肯定低得让人抓狂。 四、总结与展望 通过今天的讨论,相信大家对Spark的分布式缓存有了更深刻的认识。虽然它能带来显著的性能提升,但也并非万能药。其实啊,要想把它用得溜、用得爽,就得先搞懂它是怎么工作的,再根据具体的情况去灵活调整。不然的话,它的那些本事可就都浪费啦! 未来,随着硬件条件的不断改善以及算法优化的持续推进,相信Spark会在更多领域展现出更加卓越的表现。嘿,咱们做开发的嘛,就得有颗永远好奇的心!就跟追剧似的,新技术一出就得赶紧瞅两眼,说不定哪天就用上了呢。别怕麻烦,多学点东西总没错,说不定哪天就能整出个大招儿来! 最后,感谢大家耐心阅读这篇文章。如果你有任何疑问或者想法,欢迎随时交流!让我们一起努力,共同进步吧!
2025-05-02 15:46:14
81
素颜如水
转载文章
...文件下载过程中因网络问题或其他原因暂时中断后,能够在恢复连接或再次尝试下载时,从之前中断的位置(即断点)继续下载,而无需重新开始整个文件的下载。在文章所展示的SpringBoot代码示例中,通过处理HTTP Range请求头来实现这一功能。 HTTP请求头Range , HTTP协议中的Range请求头用于客户端向服务器请求资源的一部分,而不是整个资源。在文件下载场景下,Range头可以指定一个或多个字节范围,服务器收到这样的请求后,只返回请求范围内对应的文件内容。这使得客户端能够实现文件的分片下载与断点续传。在该篇文章介绍的SpringBoot控制器中,就利用了Range请求头的信息来判断并执行文件的切片下载操作。
2023-01-19 08:12:45
546
转载
转载文章
...化时代,操作系统安全问题的重要性日益凸显。近日,Red Hat Enterprise Linux(RHEL)发布了最新的安全更新,强化了身份验证机制,包括对PAM模块的进一步优化以抵御潜在攻击,并改进了sudoers文件配置的安全策略指导,旨在帮助管理员更精细地控制用户权限。 同时,针对密码安全方面,NIST近期发布的《数字身份指南》中,提倡采用多因素认证以及定期更换密码的做法,并强调了密码复杂度要求的新变化——从过去单纯追求长度和特殊字符组合转变为支持较长的、易记忆的短语。这一转变意味着,系统管理员在设置密码有效期时,应充分考虑新指南的精神,确保密码策略既安全又符合用户的记忆习惯。 此外,开源社区也在积极应对命令历史记录安全风险。例如,一种新的bash插件被开发出来,可实现命令历史记录加密存储,有效防止恶意攻击者通过查看历史记录获取敏感信息。而在端口扫描防御方面,除了传统的NMAP工具之外,一些实时网络监控与入侵检测系统如Zeek (前Bro)也因其高效识别异常网络活动的能力而备受瞩目。 综上所述,随着信息技术的发展和安全威胁的变化,Linux系统的账号安全管理需不断跟进最新研究和技术动态,结合文中所述的基础措施,灵活运用先进的安全技术和管理理念,构建更加稳固的操作系统安全防线。
2023-05-07 23:37:44
95
转载
转载文章
...Web 服务器的内部函数;例如,在使用 WebSphere 应用服务器时,由 Quartz 调度的作业并不能影响服务器的动态缓存和数据源。 二、java中实现定时任务分类 从实现的技术上来分类,目前主要有三种技术(或者说有三种产品): Java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务。使用这种方式可以让你的程序按照某一个频度执行,但不能在指定时间运行。一般用的较少,这篇文章将不做详细介绍。 使用Quartz,这是一个功能比较强大的的调度器,可以让你的程序在指定时间执行,也可以按照某一个频度执行,配置起来稍显复杂,稍后会详细介绍。 Spring3.0以后自带的task,可以将它看成一个轻量级的Quartz,而且使用起来比Quartz简单许多,稍后会介绍。 从作业类的继承方式来讲,可以分为两类: 作业类需要继承自特定的作业类基类,如Quartz中需要继承自org.springframework.scheduling.quartz.QuartzJobBean;java.util.Timer中需要继承自java.util.TimerTask。 作业类即普通的java类,不需要继承自任何基类。 注:个人推荐使用第二种方式,因为这样所以的类都是普通类,不需要事先区别对待。 从任务调度的触发时机来分,这里主要是针对作业使用的触发器,主要有以下两种: 每隔指定时间则触发一次,在Quartz中对应的触发器为:org.springframework.scheduling.quartz.SimpleTriggerBean 每到指定时间则触发一次,在Quartz中对应的调度器为:org.springframework.scheduling.quartz.CronTriggerBean 注:并非每种任务都可以使用这两种触发器,如java.util.TimerTask任务就只能使用第一种。Quartz和spring task都可以支持这两种触发条件。 三、Quartz与Spring的集成 第一种,作业类继承自特定的基类:org.springframework.scheduling.quartz.QuartzJobBean。 第一步:定义作业类 Java代码 import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.scheduling.quartz.QuartzJobBean; public class Job1 extends QuartzJobBean { private int timeout; private static int i = 0; //调度工厂实例化后,经过timeout时间开始执行调度 public void setTimeout(int timeout) { this.timeout = timeout; } / 要调度的具体任务 / @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { System.out.println("定时任务执行中…"); } } 第二步:spring配置文件中配置作业类JobDetailBean Xml代码 <bean name="job1" class="org.springframework.scheduling.quartz.JobDetailBean"> <property name="jobClass" value="com.gy.Job1" /> <property name="jobDataAsMap"> <map> <entry key="timeout" value="0" /> </map> </property> </bean> 说明:org.springframework.scheduling.quartz.JobDetailBean有两个属性,jobClass属性即我们在java代码中定义的任务类,jobDataAsMap属性即该任务类中需要注入的属性值。 第三步:配置作业调度的触发方式(触发器) Quartz的作业触发器有两种,分别是 org.springframework.scheduling.quartz.SimpleTriggerBean org.springframework.scheduling.quartz.CronTriggerBean 第一种SimpleTriggerBean,只支持按照一定频度调用任务,如每隔30分钟运行一次。 配置方式如下: Xml代码 <bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean"> <property name="jobDetail" ref="job1" /> <property name="startDelay" value="0" /><!-- 调度工厂实例化后,经过0秒开始执行调度 --> <property name="repeatInterval" value="2000" /><!-- 每2秒调度一次 --> </bean> 第二种CronTriggerBean,支持到指定时间运行一次,如每天12:00运行一次等。 配置方式如下: Xml代码 <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail" ref="job1" /> <!—每天12:00运行一次 --> <property name="cronExpression" value="0 0 12 ?" /> </bean> 关于cronExpression表达式的语法参见附录。 第四步:配置调度工厂 Xml代码 <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="cronTrigger" /> </list> </property> </bean> 说明:该参数指定的就是之前配置的触发器的名字。 第五步:启动你的应用即可,即将工程部署至tomcat或其他容器。 第二种,作业类不继承特定基类。 Spring能够支持这种方式,归功于两个类: org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean 这两个类分别对应spring支持的两种实现任务调度的方式,即前文提到到java自带的timer task方式和Quartz方式。这里我只写MethodInvokingJobDetailFactoryBean的用法,使用该类的好处是,我们的任务类不再需要继承自任何类,而是普通的pojo。 第一步:编写任务类 Java代码 public class Job2 { public void doJob2() { System.out.println("不继承QuartzJobBean方式-调度进行中..."); } } 可以看出,这就是一个普通的类,并且有一个方法。 第二步:配置作业类 Xml代码 <bean id="job2" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject"> <bean class="com.gy.Job2" /> </property> <property name="targetMethod" value="doJob2" /> <property name="concurrent" value="false" /><!-- 作业不并发调度 --> </bean> 说明:这一步是关键步骤,声明一个MethodInvokingJobDetailFactoryBean,有两个关键属性:targetObject指定任务类,targetMethod指定运行的方法。往下的步骤就与方法一相同了,为了完整,同样贴出。 第三步:配置作业调度的触发方式(触发器) Quartz的作业触发器有两种,分别是 org.springframework.scheduling.quartz.SimpleTriggerBean org.springframework.scheduling.quartz.CronTriggerBean 第一种SimpleTriggerBean,只支持按照一定频度调用任务,如每隔30分钟运行一次。 配置方式如下: Xml代码 <bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean"> <property name="jobDetail" ref="job2" /> <property name="startDelay" value="0" /><!-- 调度工厂实例化后,经过0秒开始执行调度 --> <property name="repeatInterval" value="2000" /><!-- 每2秒调度一次 --> </bean> 第二种CronTriggerBean,支持到指定时间运行一次,如每天12:00运行一次等。 配置方式如下: Xml代码 <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail" ref="job2" /> <!—每天12:00运行一次 --> <property name="cronExpression" value="0 0 12 ?" /> </bean> 以上两种调度方式根据实际情况,任选一种即可。 第四步:配置调度工厂 Xml代码 <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="cronTrigger" /> </list> </property> </bean> 说明:该参数指定的就是之前配置的触发器的名字。 第五步:启动你的应用即可,即将工程部署至tomcat或其他容器。 到此,spring中Quartz的基本配置就介绍完了,当然了,使用之前,要导入相应的spring的包与Quartz的包,这些就不消多说了。 其实可以看出Quartz的配置看上去还是挺复杂的,没有办法,因为Quartz其实是个重量级的工具,如果我们只是想简单的执行几个简单的定时任务,有没有更简单的工具,有! 四、Spring-Task 上节介绍了在Spring 中使用Quartz,本文介绍Spring3.0以后自主开发的定时任务工具,spring task,可以将它比作一个轻量级的Quartz,而且使用起来很简单,除spring相关的包外不需要额外的包,而且支持注解和配置文件两种 形式,下面将分别介绍这两种方式。 第一种:配置文件方式 第一步:编写作业类 即普通的pojo,如下: Java代码 import org.springframework.stereotype.Service; @Service public class TaskJob { public void job1() { System.out.println(“任务进行中。。。”); } } 第二步:在spring配置文件头中添加命名空间及描述 Xml代码 <beans xmlns="http://www.springframework.org/schema/beans" xmlns:task="http://www.springframework.org/schema/task" 。。。。。。 xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd"> 第三步:spring配置文件中设置具体的任务 Xml代码 <task:scheduled-tasks> <task:scheduled ref="taskJob" method="job1" cron="0 ?"/> </task:scheduled-tasks> <context:component-scan base-package=" com.gy.mytask " /> 说明:ref参数指定的即任务类,method指定的即需要运行的方法,cron及cronExpression表达式,具体写法这里不介绍了,详情见上篇文章附录。 <context:component-scan base-package="com.gy.mytask" />这个配置不消多说了,spring扫描注解用的。 到这里配置就完成了,是不是很简单。 第二种:使用注解形式 也许我们不想每写一个任务类还要在xml文件中配置下,我们可以使用注解@Scheduled,我们看看源文件中该注解的定义: Java代码 @Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Scheduled { public abstract String cron(); public abstract long fixedDelay(); public abstract long fixedRate(); } 可以看出该注解有三个方法或者叫参数,分别表示的意思是: cron:指定cron表达式 fixedDelay:官方文档解释:An interval-based trigger where the interval is measured from the completion time of the previous task. The time unit value is measured in milliseconds.即表示从上一个任务完成开始到下一个任务开始的间隔,单位是毫秒。 fixedRate:官方文档解释:An interval-based trigger where the interval is measured from the start time of the previous task. The time unit value is measured in milliseconds.即从上一个任务开始到下一个任务开始的间隔,单位是毫秒。 下面我来配置一下。 第一步:编写pojo Java代码 import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component(“taskJob”) public class TaskJob { @Scheduled(cron = "0 0 3 ?") public void job1() { System.out.println(“任务进行中。。。”); } } 第二步:添加task相关的配置: Xml代码 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd" default-lazy-init="false"> <context:annotation-config /> <!—spring扫描注解的配置 --> <context:component-scan base-package="com.gy.mytask" /> <!—开启这个配置,spring才能识别@Scheduled注解 --> <task:annotation-driven scheduler="qbScheduler" mode="proxy"/> <task:scheduler id="qbScheduler" pool-size="10"/> 说明:理论上只需要加上<task:annotation-driven />这句配置就可以了,这些参数都不是必须的。 Ok配置完毕,当然spring task还有很多参数,我就不一一解释了,具体参考xsd文档http://www.springframework.org/schema/task/spring-task-3.0.xsd。 附录: cronExpression的配置说明,具体使用以及参数请百度google 字段 允许值 允许的特殊字符 秒 0-59 , - / 分 0-59 , - / 小时 0-23 , - / 日期 1-31 , - ? / L W C 月份 1-12 或者 JAN-DEC , - / 星期 1-7 或者 SUN-SAT , - ? / L C 年(可选) 留空, 1970-2099 , - / - 区间 通配符 ? 你不想设置那个字段 下面只例出几个式子 CRON表达式 含义 "0 0 12 ?" 每天中午十二点触发 "0 15 10 ? " 每天早上10:15触发 "0 15 10 ?" 每天早上10:15触发 "0 15 10 ? " 每天早上10:15触发 "0 15 10 ? 2005" 2005年的每天早上10:15触发 "0 14 ?" 每天从下午2点开始到2点59分每分钟一次触发 "0 0/5 14 ?" 每天从下午2点开始到2:55分结束每5分钟一次触发 "0 0/5 14,18 ?" 每天的下午2点至2:55和6点至6点55分两个时间段内每5分钟一次触发 "0 0-5 14 ?" 每天14:00至14:05每分钟一次触发 "0 10,44 14 ? 3 WED" 三月的每周三的14:10和14:44触发 "0 15 10 ? MON-FRI" 每个周一、周二、周三、周四、周五的10:15触发 Cron 表达式包括以下 7 个字段: 秒 分 小时 月内日期 月 周内日期 年(可选字段) 特殊字符 Cron 触发器利用一系列特殊字符,如下所示: 反斜线(/)字符表示增量值。例如,在秒字段中“5/15”代表从第 5 秒开始,每 15 秒一次。 问号(?)字符和字母 L 字符只有在月内日期和周内日期字段中可用。问号表示这个字段不包含具体值。所以,如果指定月内日期,可以在周内日期字段中插入“?”,表示周内日期值无关紧要。字母 L 字符是 last 的缩写。放在月内日期字段中,表示安排在当月最后一天执行。在周内日期字段中,如果“L”单独存在,就等于“7”,否则代表当月内周内日期的最后一个实例。所以“0L”表示安排在当月的最后一个星期日执行。 在月内日期字段中的字母(W)字符把执行安排在最靠近指定值的工作日。把“1W”放在月内日期字段中,表示把执行安排在当月的第一个工作日内。 井号()字符为给定月份指定具体的工作日实例。把“MON2”放在周内日期字段中,表示把任务安排在当月的第二个星期一。 星号()字符是通配字符,表示该字段可以接受任何可能的值。 字段 允许值 允许的特殊字符 秒 0-59 , - / 分 0-59 , - / 小时 0-23 , - / 日期 1-31 , - ? / L W C 月份 1-12 或者 JAN-DEC , - / 星期 1-7 或者 SUN-SAT , - ? / L C 年(可选) 留空, 1970-2099 , - / 表达式意义 "0 0 12 ?" 每天中午12点触发 "0 15 10 ? " 每天上午10:15触发 "0 15 10 ?" 每天上午10:15触发 "0 15 10 ? " 每天上午10:15触发 "0 15 10 ? 2005" 2005年的每天上午10:15触发 "0 14 ?" 在每天下午2点到下午2:59期间的每1分钟触发 "0 0/5 14 ?" 在每天下午2点到下午2:55期间的每5分钟触发 "0 0/5 14,18 ?" 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发 "0 0-5 14 ?" 在每天下午2点到下午2:05期间的每1分钟触发 "0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:10和2:44触发 "0 15 10 ? MON-FRI" 周一至周五的上午10:15触发 "0 15 10 15 ?" 每月15日上午10:15触发 "0 15 10 L ?" 每月最后一日的上午10:15触发 "0 15 10 ? 6L" 每月的最后一个星期五上午10:15触发 "0 15 10 ? 6L 2002-2005" 2002年至2005年的每月的最后一个星期五上午10:15触发 "0 15 10 ? 63" 每月的第三个星期五上午10:15触发 每天早上6点 0 6 每两个小时 0 /2 晚上11点到早上8点之间每两个小时,早上八点 0 23-7/2,8 每个月的4号和每个礼拜的礼拜一到礼拜三的早上11点 0 11 4 1-3 1月1日早上4点 0 4 1 1 本篇文章为转载内容。原文链接:https://zhanghaiyang.blog.csdn.net/article/details/51397459。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-10-27 18:50:19
344
转载
转载文章
...能正确安装?针对这个问题,在我对自己的Windows 7进行更新的时候,有时也会发生类似的问题,经过研究,已经完美解决,下面给大家解决方案! 如果在检查更新时收到Windows Update错误80070003,则需要删除Windows用于标识计算机更新的临时文件。若要删除临时文件,请停止Windows Update服务,删除临时更新文件,重新启动Windows Update服务,然后再次尝试检查Windows更新。 以下步骤为解决Windows 7更新错误方法,本博客亲测有效。 必须以管理员身份进行登录,才能执行这些步骤。 1.单击打开“管理工具(通过单击“开始”按钮,再依次单击“控制面板”,然后单击“管理工具”。 2.双击“服务”。如果系统提示您输入管理员密码或进行确认,请键入该密码或提供确认。 3.单击“名称”列标题以逆序排列名称。找到“Windows Update”服务,右键单击该服务,然后单击“停止”。 1.打开“计算机”。 2.双击安装Windows的本地硬盘(通常是驱动器C)。 3.双击Windows文件夹,然后双击SoftwareDistribution文件夹。 4.双击打开DataStore文件夹,然后删除该文件夹中的所有文件。如果系统提示您输入管理员密码或进行确认,请键入该密码或提供确认。 5.单击“后退”按钮。在SoftwareDistribution文件夹中,双击打开Download文件夹,删除该文件夹中的所有文件,然后关闭窗口。如果系统提示您输入管理员密码或进行确认,请键入该密码或提供确认。 必须以管理员身份进行登录,才能执行这些步骤。 1.单击打开“管理工具(方法同上)”。 2.双击“服务”。如果系统提示您输入管理员密码或进行确认,请键入该密码或提供确认。 3.单击“名称”列标题以逆序排列名称。找到“Windows Update”服务,右键单击该服务,然后单击“启动”。 4.关闭“服务”窗口和“管理工具”窗口。 完成上面操作,你需要重新更新看看可以成功更新了吗,一般因为我们删除了自动更新的一些文件,如果你仔细观察的话,那些文件大小并不是很小,所以我们再更新的时候等待的时间可能会长一些! 【三】:Win10系统提示“无法完成更新正在撤销更改” 更新win10系统补丁之后,系统会提示“window10无法更新,正在撤销”,需要重启好几次,这该怎么办呢?下面小编就向大家介绍一下windows10系统无法完成更新正在撤销更改的解决方法,欢迎大家参考和学习。 系统更新失败,反复重启还是不行,那是不是下载下来的补丁没用了呢??所以我们先要删除Windows更新的缓存文件!在做以下操作之前,首先我们要确认系统内的windows update & BITS服务设置是否开启。 检查方法: 1、按“Win+R”组合键打开运行,输入“services.msc”,点击确定(如果弹出用户账户控制窗口,我们点击“继续”)。 2、双击打开“Background Intelligent Transfer Services”服务。 3、在选项卡点击“常规”,要保证“启动类型”是“自动”或者“手动”。然后点击“服务状态”“启用”按钮。 4. 重复步骤3分别对“Windows Installer”,“Cryptographic Services”, “software licensing service” 以及“Windows Update”这四项服务进行检查。 解决办法: 1、按“Windows+X”打开“命令提示符(管理员)”。 2、输入“net stop wuauserv”回车(我们先把更新服务停止)。 3、输入”%windir%\SoftwareDistribution“回车(删除Download和DataStore文件夹中的所有文件)。 4、最后输入“net start wuauserv”回车(重新开启系统更新服务)。 完成以上的步骤之后,我们就可以在“Windows Update”中再次尝试检查更新即可。 以上就是windows10系统无法完成更新正在撤销更改的解决方法介绍了。遇到同样问题的用户,可以尝试一下这个方法,如果不行,可以留言,小编会继续寻找其他的解决办法。 【四】:Windows更新失败提示错误码80070003怎么办 Windows7,Windows8.1,Windows10在更新过程中,所更新的程序无法安装,导致更新失败,提示错误码80070003。遇到这种情况,无论再试一次,或重启电脑,更新程序仍无法安装,出现错误码80070003提示。关于这个故障,下面小编就为大家介绍一下具体的解决方法吧,欢迎大家参考和学习。 具体解决方法步骤: 1、在电脑更新过程中,更新失败,程序无法安装,出现错误码80070003的提示。如图1 2、打开控制面板,点击“系统和安全”,打开对话框。如图2 3、在打开的对话框中,点击“管理工具”-双击“服务”,在打开的对话框的下方找到“Windows Update"。(如图3),选择Windows Update,点击界面左上角的”停止“按键,或是单击右键选择”停止“。(如图4),以管理员身份进入,如果提示需要输入秘码,则输入秘码。 4、在C盘,打开”Windows"文件夹,-双击打开“SoftwareDistribution"文件夹,找到下面的2个文件夹。打开”DataStore"文件夹,删除里面所有的文件。反回上一步。如图5.1,再打开"Download"文件夹,删除里面所有的文件。(如图5.2) 5、返回第三步的操作,选择Windows Update,右键单击,选择“启动”。 6、做完上面操作后,安装更新文件就会顺利了。 本篇文章为转载内容。原文链接:https://blog.csdn.net/weixin_42620202/article/details/119158423。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-02-16 16:18:33
136
转载
转载文章
...很大不同,没有侵权等问题,在法律上完全具有可行性。 综上所述,腕表交易系统在技术、经济、操作和法律上都具有很高的可行性,开发此程序是很必要的。 3.2 腕表交易系统功能需求分析 此基于SSM的腕表交易系统分前台功能和后台功能: 1)前台部分由用户使用,主要包括用户注册,腕表购物车管理,订单管理,个人资料管理,留言板管理 2)后台部分由管理员使用,主要包括管理员身份验证,商品管理,处理订单,用户信息管理,连接信息管理 3.3 数据库需求分析 数据库的设计通常是以一个已经存在的数据库管理系统为基础的,常用的数据库管理系统有MYSQL,SQL,Oracle等。我采用了Mysql数据库管理系统,建立的数据库名为db_business。 整个系统功能需要以下数据项: 用户:用户id、用户名称、登录密码、用户真实姓名、性别、邮箱地址、联系地址、联系电话、密码问题、答案、注册时间。 留言:主题id、作者姓名、Email、主题名称、留言内容、发布时间。 商品:商品id、名称、价格、图片路径、类型、简要介绍、存储地址、上传人姓名、发布时间、是否推荐。 订单:订单号、用户名、真实姓名、订购日期、Email、地址、邮编、付款方式、联系方式、运送方式、订单核对、其他。 管理员:管理员id、管理员名称、管理员密码。 公告:公告内容、公告时间。 4系统设计 4.1 系统功能模块设计 功能结构图如下: 图9 功能模块设计图 从图中可以看出,网上腕表交易系统可以分为前台和后台两个部分,前台部分由用户使用,主要包括用户注册,生成订单,腕表购物车管理,查看腕表购物车,查看留言,订购产品,订单查询和发布留言7个模块;本文转载自http://www.biyezuopin.vip/onews.asp?id=11975后台部分由管理员使用,主要包括管理员身份验证,商品管理,处理订单,用户信息管理,连接信息管理5个模块。 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><base href="<%=basePath%>"/><title>腕表商城</title><meta http-equiv="pragma" content="no-cache"><meta http-equiv="cache-control" content="no-cache"><meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"><meta http-equiv="description" content="This is my page"><meta name="viewport" content="width=device-width, initial-scale=1"><!-- Favicon --><link rel="shortcut icon" type="image/x-icon" href="img/favicon.png"><link rel="stylesheet" type="text/css" href="<%=basePath%>home/css/font-awesome.min.css" /><link rel="stylesheet" type="text/css" href="<%=basePath%>home/css/bootstrap.css" /><link rel="stylesheet" type="text/css" href="<%=basePath%>home/css/style.css"><link rel="stylesheet" type="text/css" href="<%=basePath%>home/css/magnific-popup.css"><link rel="stylesheet" type="text/css" href="<%=basePath%>home/css/owl.carousel.css"><script type="text/javascript">function getprofenlei(){ var html = ""; $.ajax({url: "leixing.action?list&page=0&rows=30",type: "POST",async: false, contentType: "application/x-www-form-urlencoded;charset=UTF-8",success: function (data) { $.each(data.rows, function (i, val) { html += ' <li ><a href="home/search.jsp?fenlei='+val.id+'" >'+val.a1+' </a></li>';})} }); $("fenlei").html(html);}function gettop1(){var html = "";$.ajax({url: "leixing.action?list&page=0&rows=10",type: "POST",async: false,success: function (data) {var total='';//<div class="tab-pane active" id="nArrivals">// <div class="nArrivals owl-carousel" id="top1">$.each(data.rows, function (i, valmm) { html+='<div class="nArrivals owl-carousel" id="'+valmm.id+'">';$.ajax({url: "shangpin.action?list&page=0&rows=10",type: "POST",async: false,data: { fenlei:valmm.id },success: function (data) { $.each(data.rows, function (i, val) { html+='<div class="product-grid">'+'<div class="item">'+' <div class="product-thumb">'+' <div class="image product-imageblock"> <a href="home/details.jsp?ids='+val.id+'"> <img data-name="product_image" style="width:223px;height:285px;" src="<%=basePath%>'+val.tupian1+'" alt="iPod Classic" title="iPod Classic" class="img-responsive"> <img style="width:223px;height:285px;" src="<%=basePath%>'+val.tupian1+'" alt="iPod Classic" title="iPod Classic" class="img-responsive"> </a> </div>'+' <div class="caption product-detail text-left">'+' <h6 data-name="product_name" class="product-name mt_20"><a href="home/details.jsp?ids='+val.id+'" title="Casual Shirt With Ruffle Hem">'+val.biaoti+'</a></h6>'+' <div class="rating"> <span class="fa fa-stack"><i class="fa fa-star-o fa-stack-1x"></i><i class="fa fa-star fa-stack-1x"></i></span> <span class="fa fa-stack"><i class="fa fa-star-o fa-stack-1x"></i><i class="fa fa-star fa-stack-1x"></i></span> <span class="fa fa-stack"><i class="fa fa-star-o fa-stack-1x"></i><i class="fa fa-star fa-stack-1x"></i></span> <span class="fa fa-stack"><i class="fa fa-star-o fa-stack-1x"></i><i class="fa fa-star fa-stack-1x"></i></span> <span class="fa fa-stack"><i class="fa fa-star-o fa-stack-1x"></i><i class="fa fa-star fa-stack-x"></i></span> </div>'+'<span class="price"><span class="amount"><span class="currencySymbol">$</span>'+val.jiage+'</span>'+'</span>'+'<div class="button-group text-center">'+' <div class="wishlist"><a href="home/details.jsp?ids='+val.id+'"><span>wishlist</span></a></div>'+'<div class="quickview"><a href="home/details.jsp?ids='+val.id+'"><span>Quick View</span></a></div>'+'<div class="compare"><a href="home/details.jsp?ids='+val.id+'"><span>Compare</span></a></div>'+'<div class="add-to-cart"><a href="home/details.jsp?ids='+val.id+'"><span>Add to cart</span></a></div>'+'</div>'+'</div>'+'</div>'+'</div>'+' </div>'; })html+='</div>'; } })}) $("nArrivals").html(html); } }); 本篇文章为转载内容。原文链接:https://blog.csdn.net/newlw/article/details/127608579。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-03-21 18:24:50
66
转载
转载文章
...背景下的数字识别差异问题,有研究团队正着手构建包含多元书写风格的全球手写数字数据库,以期通过更全面的数据训练,提升各类设备对手写数字识别的普适性和准确性。同时,也有科研人员积极探索新的图像预处理技术和网络优化算法,如超分辨率技术、注意力机制等,进一步提高识别系统的鲁棒性和精度。 值得注意的是,云端训练与边缘计算的结合正在为OpenMV等嵌入式设备提供强大的后盾支持。例如,阿里云IoT部门最近推出的云端-边缘协同训练方案,允许用户在云端完成大规模数据训练后,将轻量化模型部署至OpenMV等终端设备上,既保证了模型性能,又降低了设备存储和计算压力,对于推动智能硬件在数字识别领域的广泛应用具有深远意义。 总之,在当今AI技术蓬勃发展的大背景下,OpenMV作为微型计算机视觉平台的角色愈发重要,其在手写数字识别项目中的实践不仅体现了技术的先进性,也昭示着未来物联网设备智能化的发展趋势。
2024-01-10 08:44:41
282
转载
转载文章
...:解决资源利用率低的问题 桌面虚拟化:有一些弊端,图形显示层面会有问题 应用虚拟化:没接触过,公司比较穷买不起,基本上只有银行等国企才会用Xenapp ICA 八、虚拟化工具KVM介绍 KVM 全称:Kernel-based Virtual Machine(内核级虚拟化机器) 原本由以色列人创建,现在被红帽收购 ESXI 虚拟套件,现在是免费使用 VMware vSphere Hypervisor – 安装和配置 提示:一台服务器首选ESXI 九、KVM安装 调整虚拟机 虚拟化Intel使用的是Intel VT-X ; 虚拟化AMD使用的是AMD-V 创建虚拟机步骤 1.准备虚拟机硬盘 2.需要系统iso镜像3.需要安装一个vnc的客户端来连接 查看系统环境 [root@linux-node1 ~] cat /etc/redhat-release CentOS Linux release 7.2.1511 (Core) [root@linux-node1 ~] uname -r 3.10.0-327.36.2.el7.x86_64 检查是否有vmx或者svm [root@linux-node1 ~] grep -E '(vmx|svm)' /proc/cpuinfo 安装kvm用户态模块 [root@linux-node1 ~] yum list|grep kvm libvirt-daemon-kvm.x86_64 1.2.17-13.el7_2.5 updates pcp-pmda-kvm.x86_64 3.10.6-2.el7 base qemu-kvm.x86_64 10:1.5.3-105.el7_2.7 updates qemu-kvm-common.x86_64 10:1.5.3-105.el7_2.7 updates qemu-kvm-tools.x86_64 10:1.5.3-105.el7_2.7 updates [root@linux-node1 ~] yum install qemu-kvm qemu-kvm-tools libvirt -y libvirt 用来管理kvm kvm属于内核态,不需要安装。但是需要一些类似于依赖的 kvm属于内核态,不需要安装。但是需要安装一些类似于依赖的东西 启动 [root@linux-node1 ~] systemctl start libvirtd.service [root@linux-node1 ~] systemctl enable libvirtd.service 启动之后我们可以使用ifconfig进行查看,libvirtd已经为我们安装了一个桥接网卡 libvirtd为我们启动了一个dnsmasqp,这个主要是用来dhcp连接的,这个工具会给我们的虚拟机分配IP地址 [root@linux-node1 ~] ps -ef|grep dns nobody 5233 1 0 14:27 ? 00:00:00 /sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf --leasefile-ro --dhcp-script=/usr/libexec/libvirt_leaseshelper root 5234 5233 0 14:27 ? 00:00:00 /sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf --leasefile-ro --dhcp-script=/usr/libexec/libvirt_leaseshelperoot 5310 2783 0 14:31 pts/0 00:00:00 grep --color=auto dns 查看磁盘空间大小 最好是20G以上 [root@linux-node1 tmp] df -h 上传镜像 提示:如果使用rz上传镜像可能会出现错误,所以我们使用dd命令,复制系统的镜像。只需要挂载上光盘即可 [root@linux-node1 opt] dd if=/dev/cdrom of=/opt/CentOS-7.2.iso [root@linux-node1 opt] ll total 33792 -rw-r--r-- 1 root root 34603008 Jun 12 18:18 CentOS-7.2-x86_64-DVD-1511.iso 下载VNC 下载地址:http://www.tightvnc.com/download/2.8.5/tightvnc-2.8.5-gpl-setup-64bit.msi 安装完VNC如下图 创建磁盘 提示: qemu-img软件包是我们安装qemu-kvm-tools 依赖给安装上的 [root@linux-node1 opt] qemu-img create -f raw /opt/CentOS-7.2-x86_64.raw 10GFormatting '/opt/Centos-7-x86_64.raw', fmt=raw size=10737418240 [root@linux-node1 opt] [root@linux-node1 opt] ll /opt/Centos-7-x86_64.raw -rw-r--r-- 1 root root 10737418240 Oct 26 14:53 /opt/Centos-7-x86_64.raw-f 制定虚拟机格式,raw是裸磁盘/opt/Centos 存放路径 10G 代表镜像大小 安装启动虚拟机的包 [root@linux-node1 tmp] yum install -y virt-install 安装虚拟机 [root@linux-node1 tmp] virt-install --help 我们可以指定虚拟机的CPU、磁盘、内存等 [root@linux-node1 opt] virt-install --name CentOS-7.2-x86_64 --virt-type kvm --ram 1024 --cdrom=/opt/CentOS-7.2.iso --disk path=/opt/CentOS-7.2-x86_64.raw --network network=default --graphics vnc,listen=0.0.0.0 --noautoconsole --name = 给虚拟机起个名字 --ram = 内存大小 --cdrom = 镜像位置,就是我们上传iso镜像的位置,我放在/tmp下了 --disk path = 指定磁盘--network network= 网络配置 default 就会用我们刚刚ifconfig里面桥接的网卡--graphics vnc,listen= 监听vnc, 分区说明 提示:我们不分交换分区,因为公有云上的云主机都是没有交换分区的 十、Libvirt介绍 libvirt是一个开源免费管理工具,可以管理KVM、VMware等 他需要起一个后台的进程,它提供了API。像openstack就是通过libvirt API来管理虚拟机 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vcp4lgAZ-1596980494935)(libvirt.jpg)] 二、KVM虚拟机和VMware区别 虚拟机监控程序(KVM)是虚拟化平台的根基。从传统供应商到各种开源替代品,可供选择的虚拟机监控程序有很多。 VMware 是一款实现虚拟化的热门产品,可以提供 ESXi 虚拟机监控程序和 vSphere 虚拟化平台。 基于内核的虚拟机(KVM)则是 Linux® 系统上的一种开源解决方案。 VMware vSphere 与 VMware ESXi VMware 可以提供 ESXi 虚拟机监控程序和 vSphere 虚拟化平台。VMware ESXi 是一个能够直接安装到物理服务器上的裸机虚拟机监控程序,可以帮你整合硬件。你可以用 VMware 的虚拟化技术来创建和部署虚拟机(VM),从而现代化改造自己的基础架构,来交付和管理各种新旧应用。 选用 VMware vSphere 后,你需要使用 VMware 的控制堆栈来管理虚拟机,而且有多个许可证授权级别可供使用。 KVM 开源虚拟化技术 KVM 是一种开源虚拟化技术,能将 Linux 内核转变成可以实现虚拟化的虚拟机监控程序,而且可以替代专有的虚拟化技术(比如 VMware 提供的专有虚拟化技术)。 迁移到基于 KVM 的虚拟化平台,你就可以检查、修改和完善虚拟机监控程序背后的源代码。能够访问源代码,就如同掌握了开启无限可能的钥匙,能够让你虚拟化传统工作负载和应用,并为云原生和基于容器的工作负载奠定基础。由于 KVM 内置于 Linux 内核中,所以使用和部署起来非常方便。 KVM 虚拟机和 VMware vSphere 的主要区别 VMware 可以提供一个完善稳定的虚拟机监控程序,以及出色的性能和多样化的功能。但是,专有虚拟化会阻碍你获得开展云、容器和自动化投资所需的资源。解除供应商锁定,你就可以任享自由、灵活与丰富的资源,从而为未来的云原生和容器化环境打下基础。 生产就绪型的 KVM 具有支持物理和虚拟基础架构的功能,可以让你以更低的运营成本为企业工作负载提供支持。相比使用 VMware vSphere 等其他解决方案,选用基于 KVM 的虚拟化选项能够带来很多优势。 开源Linux KVM的优势: 更低的总拥有成本,从而省下运营预算,用来探索现代化创新技术。 不再受供应商捆绑。无需为不用的产品付费,也不会受到软件选择限制。 跨平台互操作性:KVM 可以在 Linux 和 Windows 平台上运行,所以你可以充分利用现有的基础架构投资。 出色简便性:可以通过单个虚拟化平台,在数百个其他硬件或软件上创建、启动、停止、暂停、迁移和模板化数百个虚拟机。 卓越性能:应用在 KVM 上的运行速度比其他虚拟机监控程序都快。 开源优势:不但能访问源代码,还能灵活地与各种产品集成。 享受 Linux 操作系统的现有功能: 安全防护功能 内存管理 进程调度器 设备驱动程序 网络堆栈 红帽 KVM 企业级虚拟化的优势 选择红帽® 虚拟化,就等于选择了 KVM。红帽虚拟化是一款适用于虚拟化服务器和技术工作站的完整基础架构解决方案。红帽虚拟化基于强大的红帽企业 Linux® 平台和 KVM 构建而成,能让你轻松、敏捷、安全地使用资源密集型虚拟化工作负载。红帽虚拟化可凭借更加优越的性能、具有竞争力的价格和值得信赖的红帽环境,帮助企业优化 IT 基础架构。 红帽的虚拟化产品快速、经济、高效,能够帮助你从容应对当前的挑战,并为未来的技术发展奠定基础。VMware 等供应商提供的纵向扩展虚拟化解决方案不但成本高昂,而且无法帮助企业完成所需的转型,因而难以支持在混合云中运行云原生应用。要转而部署混合云环境,第一步要做的就是摆脱专有虚拟化。 红帽虚拟化包含 sVirt 和安全增强型 Linux(SELinux),是红帽企业 Linux 专为检测和预防当前 IT 环境中的复杂安全隐患而开发的技术。 业完成所需的转型,因而难以支持在混合云中运行云原生应用。要转而部署混合云环境,第一步要做的就是摆脱专有虚拟化。 红帽虚拟化包含 sVirt 和安全增强型 Linux(SELinux),是红帽企业 Linux 专为检测和预防当前 IT 环境中的复杂安全隐患而开发的技术。 借助红帽虚拟化,你可以尽享开源虚拟机监控程序的所有优势,还能获得企业级技术支持、更新和补丁,使你的环境保持最新状态,持续安心运行。开源和 RESTful API,以及 Microsoft Windows 的认证,可帮你实现跨平台的互操作性。提供的 API 和软件开发工具包(SDK)则有助于将我们的解决方案扩展至你现有和首选管理工具,并提供相关支持。 本篇文章为转载内容。原文链接:https://blog.csdn.net/qq_34799070/article/details/107900861。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-04-06 08:58:59
121
转载
转载文章
...对大家有帮助,如果有问题欢迎私信我交流~~~ 如果对你有帮助记得点个赞哦🙈🙈🙈 PS:以下的个人简历/个人陈述/老师推荐信等材料如果有需要的,欢迎关注我的 微 信 公 号【驭风者小窝】发 送【 保研 】领取大礼包~~ 二、个人情况 学校:末流985 专业排名:5% 四六级:515/449 科研竞赛:学过一些机器学习的知识,有几个简单的科研项目;一些比赛获奖,国奖 最终去向:北航计算机学硕 三、关于保研(前期准备/时间安排/个人材料) 专业知识复习:建议在大三下学期开学初期就开始复习专业课,包括:线代、概率论、数据结构、计网、计组、操作系统等(不用复习的特别深入),有的学校有笔试,大多数在面试时会问到一些基础知识(如果老师问到的基础知识都答上来,老师对你的印象肯定会特别好!)。 信息搜集:各学校/学院官网(研招网);学长学姐;保研论坛,微信公众号(后保研、保研人、保研论坛等);QQ群等。同时也要多与同学交流,互相交换信息。 搜集你想去并且基本能去的学校的要求和特点(南京大学夏令营对机考特别看重,难度也比较大,可以在大三就多刷题好好准备),进行一定的准备,可以在网上搜索相关的经验贴。 个人定位:了解你们学校学长学姐的保研去处,最好多跟本校已经保研的学长学姐交流,根据他们的经历以及自己的实力和研究生规划来对自己进行定位。 方向和选择: 人工智能?CV? NLP? 数据库?分布式系统?其他? 硕士?直博? 小老师?大牛老师? 以上这些选择因人而异,最好自己多了解、多与老师学长学姐交流,根据自己的兴趣、目前的发展以及自己未来的规划进行抉择。 夏令营(4-7月):从四月份开始就有的学校开始了夏令营申请,5-6月是夏令营申请的集中时间;参加夏令营基本都在6-7月份。夏令营的好处:老师名额多;时间比较充裕,可以较好的了解学校以及方向等;大多学校夏令营安排住宿。参加夏令营最重要的是专业排名(这是大多数学校初筛的最重要的依据,科研经历/比赛等都是次要的。当然顶会和ACM大牛除外)。 预推免(7-9月):有的学校夏令营开始后马上就开始预推免的报名与进行(例如哈工大从7月份开始到9月份有四批预推免的面试);大多数学校集中在9月中旬。如果夏令营已经有offer了可以在预推免时冲击更好的offer;如果夏令营没有拿到offer,建议此时以稳重为好。 九推:9月28号在推免系统正式填报推免志愿,录取。 个人简历:建议在寒假期间就把自己大学的经历都整理一遍,写好简历的初始版本;然后再找老师、学长学姐帮忙完善。 个人陈述:包括自己的情况介绍、科研经历、研究生期间的规划等,1000-1500字。网上有模板可以借鉴。 老师推荐信:基本都是自己写好找老师签字,如果老师能帮你手写的话,那太好不过了。 联系老师邮件:建议提前写好一个大概的模板,注意格式、内容以及邮件的标题等(例如XX大学-XXX-保研申请)。建议夏令营前或者初审过了及时联系自己喜欢的老师。 以上只是对各方面的简单介绍,每个方面详细的注意点网上好多资料,多多搜集就好。 PS:以上个人简历/个人陈述/老师推荐信模板如果有需要的私信我分享给你! 建议把以上材料都提前收集整理好,保研结束后发现我的材料文件夹3个多G...... 一年多来整理的保研资料 四、上科大信息学院夏令营(7.3-7.6) 本来没有打算报名上科大,一个同学把上科大宣传单给了我一份,看后感觉上科大实力比较强(虽然不是982/211)就报名了。 校园环境 上科大3号报到,4号-6号有开营活动、参观、自己联系老师面试(后来才知道即使拿到优营九月份也要再来面试,也就是说上科大夏令营拿到优营只是免去了九月预推免面试的初审,但是如果你足够优秀,老师比较中意,九月份就是来走一下过场。) 我参加了三个老师的面试。YY老师只是简单问了几个问题,有点水;HXM老师有一轮笔试(考的概率论比较多,编译原理、操作系统、计网也有涉及)+面试;YJY老师的一轮面试是课题组的学长学姐面的(自我介绍+项目),二轮面试和老师聊。 上科大给我的感觉就是学校小而精;老师比较好(比如YJY/GSH/TKW)、科研氛围浓厚、硬件设施完善(双人宿舍,独立卫浴,中央空调;学校地下全是停车场,下雨不用打伞可以直接走地下),但是由于建立才几年的时间,知名度不高。 学生宿舍 五、北理计算机夏令营(7.8-7.10) 北理今年入营的基本都是985和顶尖211,夏令营去了基本都能拿到优营!入营290+,夏令营参营240+,优营220+。 在北理主楼俯瞰 8号报到,领取宿舍钥匙、校园卡(北理夏令营包括食宿,每人发了一张100元的校园卡,可以在食堂、超市消费)。北理校园比较小、路比较窄;研究生宿舍三栋高层,有电梯,四人间,宿舍空间小、比较挤,大多数宿舍有空调(据说是宿舍的同学自己买或者租的),每一层有一个公共洗澡间。 9号上午宣讲,下午机试。机试两道题目难度不大,老师手动输入三个样例给分(4+3+3,每道题目满分10分)。下午机试结束我找到提前联系的LX老师聊了一个小时,老师人很nice,专心学术(据说她的研究生大都有一篇顶会论文)。 10号上午自己找老师面试。我又参加了院长实验室的面试,比较简单。下午正式面试,分了十多个组一起面试,总共四个小时。面试包括英文自我介绍、项目、研究生规划、是否打算读博、基础知识等,每人大概5-7分钟。面试结束就可以离校了。 六、北航计算机夏令营(7.11-7.14) 北航是不包含食宿的,所以入营人数较多,有600+。北航7.11上午报到+宣讲,下午机试分两组。北航机试类似CSP,可以多次提交,以最后一次为准,但是提交后不能实时出成绩。机试两个小时,包括两道题目,第一道题目比较简单,第二道题目稍微难一些,我第二道题目没有写完但是也过了机试,第二道题目即使没有写完也要能写多少写多少,把代码的思路写出来(有可能会人工判)。北航机试可以用CSP成绩代替,基本250分及以上就没问题,每年具体的情况不一样。11号晚上出机试通过名单(大概500+进340+)。 12号分组面试,每人20分钟,从上午八点一直面试到下午三点。面试包括抽取一道政治题谈看法、抽取一段英文读并翻译、基础知识(数学知识+计算机知识)、项目。政治题和英文翻译感觉大家都差不多(除非你英语特别差),主要的是基础知识面试,北航比较爱问数学问题线代、概率论、离散、高数;如果你的项目比较好的话,老师会着重问你的项目。问到我的问题有梯度、可微和可导、大数定理+中心极限定理等。12号晚上出优营名单,大概340+进180。北航是根据夏令营面试排名来定学硕和专硕的,大概有40个学硕的名额,其他都是专硕,不过北航学硕和专硕培养方式没有区别。 这是在我前面面试同学被问到的部分问题 13号领导师意向表,找导师签字,如果没有找到暑假期间或者九月份也可以再联系老师。 14号校医院体检,夏令营结束。 七、计算所(7.13-7.16) 计算所入营还是比较有难度的,但是即使没入营也可以自己联系老师,如果老师同意可以来参加面试,只是夏令营包括食宿,没入营的不包括食宿。计算所是分实验室面试的,可以参加多个实验室的面试,我参加了网数和智信的笔试+机试+面试。 智信12号笔试,14号机试+面试。笔试包括英文论文理解翻译、概率论题、计算机基础知识题目(操作系统,计网等)、CV题目(智信主要是做CV)。机试五道题目,一个小时,题目代码已经写好了,只需你补全,类似LeetCode,在学长的电脑上完成,有C++和Python可选,两种编程语言题目不同。C++用的是VS2017,会由人给你记每道题目完成的时间,会让你演示调试,结束后打包发送到一个邮箱里。 网数只有机试和面试,13号上午机试,15号面试。机试一个小时七道题目,在自己电脑上写然后拷到老师的优盘上。考察了包括链表、二叉树、图等,偏向于工程,据说今年的题目是计算所一个工程博士出的。机试70人,进入面试60人。面试每人15分钟,包括自我介绍,专业知识,是否读博,项目等。 计算所环境 八、一些建议和感想 一些建议: 提前准备,给自己定位,有针对性的准备,多在网上找经验贴;多和本校保研的学长学姐交流,多和同学交流,多搜集信息; 4月份前把简历、推荐信、个人陈述等写好,再不断修改完善; 最好能提前联系一个老师,以免拿到优营而没有找到好老师; 准备好专业知识,线代、概率论、数据结构、计网、计组、操作系统等; 如果编程能力不是特别强,最好大三开始就刷题,LeetCode的中档题难度基本就够用了; 一些体会与感想: 机会是留给有准备的人的,越努力越幸运! 做最坏的打算,做最好的准备。 保研是一场马拉松,坚持到底就是胜利。 遵道而行,但到半途需努力;会心不远,欲登绝顶莫辞劳。 也送给自己一句话:流年笑掷,未来可期! 以上仅代表个人观点与感想,如果对你有帮助记得点赞哦~如有问题,可以关注我的公主号【驭风者小窝】,我会尽我最大的努力帮助你! 本篇文章为转载内容。原文链接:https://blog.csdn.net/weixin_28983299/article/details/118319985。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-05-02 23:03:36
120
转载
转载文章
...g组件性能、处理并发问题以及改善用户体验的实际案例和建议,这些都能帮助你更好地运用Swing进行复杂GUI的设计与实现。 综上所述,不断跟进最新的GUI开发趋势和技术发展,结合实际项目需求,灵活运用和扩展Swing或其他相关框架,将有助于打造更为出色和易用的桌面应用程序。
2023-01-18 08:36:23
525
转载
转载文章
... //已存在标签的最小开始索引int existsMaxEnd = 0; //已存在标签的最大结束索引bool isContinue = true; //标签值是否连续string[] existsTags = this.readResult.Keys.ToArray<string>();foreach (string tag in existsTags){if (tag.StartsWith(String.Format("{0}{1}.", groupNamePrefix, group.Block)) && tag.Contains(".") && tag.Contains("-")){string[] tagname = tag.Split(new char[] { '.' });if (tagname.Length == 2){beginend = tagname[1].Split(new char[] { '-' });if (beginend.Length == 2){parseResult = int.TryParse(beginend[0], out begin);if (parseResult){parseResult = int.TryParse(beginend[1], out end);}region 计算最小开始索引和最大结束索引if (begin < existsMinBegin){existsMinBegin = begin;region 判断标签值是否连续if (existsMaxEnd != 0 && begin != existsMaxEnd + 1){isContinue = false;}endregion}if (end > existsMaxEnd){existsMaxEnd = end;}endregion} }if (parseResult){if (start >= begin && stop <= end){exists = true;break;}if (isContinue){if (start >= existsMinBegin && stop <= existsMaxEnd){exists = true;break;} }} }} }endregionif (!exists){ushort[] groupData = new ushort[currLen];this.readResult[tagFullName] = groupData;Console.WriteLine(tagFullName);} }}//int tagCount = group.Len % this.stepLen == 0 ? group.Len / this.stepLen : group.Len / this.stepLen + 1;//int currLen = 0;//for (int i = 0; i < tagCount; i++)//{// string tagName = String.Empty;// if (tagCount == 1)// {// tagName = String.Format("{0}-{1}", group.Start, group.Start + group.Len - 1);// currLen = group.Len;// }// else if (i == tagCount - 1)// {// tagName = String.Format("{0}-{1}", group.Start + (i this.stepLen), group.Start + (i this.stepLen) + (group.Len % this.stepLen == 0 ? this.stepLen : group.Len % this.stepLen) - 1);// currLen = group.Len % this.stepLen;// }// else// {// tagName = String.Format("{0}-{1}", group.Start + (i this.stepLen), group.Start + (i this.stepLen) + this.stepLen - 1);// currLen = this.stepLen;// }// string tagFullName = String.Format("{0}{1}.{2}", groupNamePrefix, group.Block, tagName);// if (!this.readResult.ContainsKey(tagFullName))// {// short[] groupData = new short[currLen];// this.readResult[tagFullName] = groupData;// }//} }endregionregion 开启内部定时读取if (this.innerReadThread == null){this.innerReadRate = this.Main.ReadHz / 2;this.innerReadThread = new System.Threading.Thread(this.InnerAutoRead);this.innerReadThread.Start();}endregion}return this.State;} }/// <summary>/// 从设备读取数据/// </summary>/// <param name="block">要读取的块号</param>/// <param name="start">要读取的起始字</param>/// <param name="len">要读取的长度</param>/// <param name="buff">读取成功后的输出数据</param>/// <returns>成功返回true,失败返回false</returns>public override bool Read(string block, int start, int len, out object[] buff){lock (this){buff = null;if (this._isClosing){return false;}string readstrflag = String.Format("{0}{1}.{2}-{3}", this.groupNamePrefix, block, start, start + len - 1);System.Text.StringBuilder sbtaglength = new System.Text.StringBuilder();string startTag = String.Empty;string groupName = String.Format("{0}{1}", this.groupNamePrefix, block); //要读取的OPCServer块List<ushort> groupData = new List<ushort>();List<string> groupTagNames = new List<string>();int startIndex = 0;try{if (!Open()){return false;}//return true;string[] keys = this.readResult.Keys.ToArray<string>();foreach (string key in keys){if (key.StartsWith(groupName) && key.Replace(String.Format("{0}.", groupName), String.Empty).Contains("-")){groupTagNames.Add(key);} }groupTagNames.Sort(); //对块标签进行排序foreach (string key in groupTagNames){if (String.IsNullOrEmpty(startTag)){startTag = key.Replace(String.Format("{0}.", groupName), String.Empty);}ushort[] values;if (this.readResult[key] is ushort[]){values = this.readResult[key] as ushort[];}else{values = new ushort[] { (ushort)this.readResult[key] };}sbtaglength.Append(String.Format("tagName={0}, buff length = {1}", key, values.Length));groupData.AddRange(values);}buff = new object[len];if (!String.IsNullOrEmpty(startTag)){string strStartIndex = startTag.Substring(0, startTag.IndexOf("-"));int.TryParse(strStartIndex, out startIndex);startIndex = start - startIndex;Array.Copy(groupData.ToArray(), startIndex, buff, 0, buff.Length);}else{}return true;}catch (Exception ex){Console.WriteLine(String.Join(";", groupTagNames.ToArray<string>()));Console.WriteLine("data length = " + groupData.Count);Console.WriteLine(this.Name + "读取失败[" + readstrflag + "]:" + ex.Message);Console.WriteLine(sbtaglength.ToString());this.State = false;return false;} }}/// <summary>/// 写入数据到设备/// </summary>/// <param name="block">要写入的块号</param>/// <param name="start">要写入的起始字</param>/// <param name="buff">要写如的数据</param>/// <returns>成功返回true,失败返回false</returns>public override bool Write(int block, int start, object[] buff){bool result = true;lock (this){try{if (this._isClosing){return false;}if (!Open()){return false;}bool isWrite = false;region 按标签变量写入string itemId = "";foreach (Equips.BaseInfo.Group group in this.Group.Values){if (group.Block == block.ToString()){foreach (Equips.BaseInfo.Data data in group.Data.Values){if (group.Start + data.Start == start && data.Len == buff.Length){if (this.dicTags.ContainsKey(data.Name)){itemId = this.dicTags[data.Name];}break;} }} }if (!String.IsNullOrEmpty(itemId)){UInt16[] intBuff = new UInt16[buff.Length];for (int i = 0; i < intBuff.Length; i++){intBuff[i] = 0;if (!UInt16.TryParse(buff[i].ToString(), out intBuff[i])){Console.WriteLine("在写入OPCUA标签时把buff中的元素转为UInt16类型失败!");} }result = this.myOpcHelper.WriteUInt16(itemId, intBuff);if (!result){Console.WriteLine(String.Format("标签变量[{0}]写入失败!", itemId));return false;}else{Console.WriteLine("按标签变量写入..." + itemId);isWrite = true;} }if (isWrite){return true;}endregionregion 按块写入region 先读取相应标签数数据string startTag = String.Empty;string groupName = String.Format("{0}{1}", this.groupNamePrefix, block); //要读取的OPCServer块List<ushort> groupData = new List<ushort>();string[] keys = readResult.Keys.Where(o => o.StartsWith(groupName) && o.Contains("-")).OrderBy(c => c).ToArray<string>();foreach (string key in keys){if (String.IsNullOrEmpty(startTag)){startTag = key.Replace(String.Format("{0}.", groupName), String.Empty);}string[] beginEnd = key.Replace(String.Format("{0}.", groupName), String.Empty).Split(new char[] { '-' });if (beginEnd.Length != 2){Console.WriteLine(String.Format("标签变量[{0}]未按约定方式命名,请按[DB块号].[起始字-结束字]方式标签变量进行命名!", String.Format("{0}.{1}", key)));return false;}int begin = 0;int end = 0;int.TryParse(beginEnd[0], out begin);int.TryParse(beginEnd[1], out end);region 写入之前,先读取一下PLC的值if ((start >= begin && start <= end) || ((start + buff.Length - 1) >= begin && (start + buff.Length - 1) <= end) || (start < begin && (start + buff.Length - 1) > end)){this.ReadTag(key);if (this.readResult.ContainsKey(key) && this.readResult[key] is Array){Console.WriteLine("read = " + key);groupData.AddRange(this.readResult[key] as ushort[]);}else{Console.WriteLine(String.Format("读取结果中不包含标签变量[{0}]的值!", String.Format("{0}", key)));} }else{if (this.readResult.ContainsKey(key) && this.readResult[key] is Array){Console.WriteLine("no read = " + key);groupData.AddRange(this.readResult[key] as ushort[]);} }endregion}endregionif (String.IsNullOrEmpty(startTag)){Console.WriteLine("写入失败,未在OPCUAserver中找到对应的标签,block = {0}, start = {1}, len = {2}", block, start, buff.Length);return false;}region 更新标签中对应的数据后,再写回OPCServerint startIndex = 0;string strStartIndex = startTag.Substring(0, startTag.IndexOf("-"));int.TryParse(strStartIndex, out startIndex);startIndex = start - startIndex;ushort[] newDataBuffer = groupData.ToArray();for (int i = 0; i < buff.Length; i++){ushort svalue = 0;ushort.TryParse(buff[i].ToString(), out svalue);newDataBuffer[startIndex + i] = svalue;}int index = 0;string[] keys2 = readResult.Keys.Where(o => o.StartsWith(groupName) && o.Contains("-")).OrderBy(c => c).ToArray<string>();foreach (string key2 in keys2){string[] beginEnd = key2.Replace(String.Format("{0}.", groupName), String.Empty).Split(new char[] { '-' });if (beginEnd.Length != 2){Console.WriteLine(String.Format("标签变量[{0}]未按约定方式命名,请按[DB块号].[起始字-结束字]方式标签变量进行命名!", String.Format("{0}", key2)));return false;}int begin = 0;int end = 0;int.TryParse(beginEnd[0], out begin);int.TryParse(beginEnd[1], out end);if ((start >= begin && start <= end) || ((start + buff.Length - 1) >= begin && (start + buff.Length - 1) <= end) || (start < begin && (start + buff.Length - 1) > end)){//Console.WriteLine("---------------------------------------------------------");//Console.WriteLine("start = " + start);//Console.WriteLine("start + buff.Length - 1 = " + (start + buff.Length -1));//Console.WriteLine("begin = " + begin);//Console.WriteLine("end = " + end);//Console.WriteLine("---------------------------------------------------------");if (!this.dicTags.ContainsKey(key2)){Console.WriteLine(String.Format("写入失败:标签变量[{0}]在OpcUA Server中未定义!", String.Format("{0}", key2)));return false;}int len = (this.readResult[key2] as ushort[]).Length;ushort[] tagDataBuff = new ushort[len];//Console.WriteLine("newDataBuff");//Console.WriteLine(String.Join(",", newDataBuffer));//Console.WriteLine("index = " + index);//Console.WriteLine("tagDataBuff.Length = " + tagDataBuff.Length);//Array.Copy(newDataBuffer, begin, tagDataBuff, 0, tagDataBuff.Length);int existsMinBegin = this.GetExistsMinBeginByBlock(block.ToString());Array.Copy(newDataBuffer, begin - existsMinBegin, tagDataBuff, 0, tagDataBuff.Length);index += tagDataBuff.Length;//Console.WriteLine("Write " + key2);//Console.WriteLine(String.Join(",", tagDataBuff));//Console.WriteLine("写入标签:" + this.dicTags[key2]);result = this.myOpcHelper.WriteUInt16(this.dicTags[key2], tagDataBuff);if (!result){Console.WriteLine(String.Format("向标签变量[{0}]中写入值失败!", String.Format("{0}", key2)));return false;}else{this.ReadTag(key2);Console.WriteLine("写入...");}//Console.WriteLine("---------------------------------------------------------");} }endregionendregionreturn result;}catch (Exception ex){Console.WriteLine(this.Name + "写入失败:" + ex.Message);return false;} }}/// <summary>/// 关闭方法,断开与设备的连接释放资源/// </summary>public override void Close(){try{this._isClosing = true;System.Threading.Thread.Sleep(this.Main.ReadHz);if (this.innerReadThread != null){this.innerReadThread.Abort();this.innerReadThread = null;} }catch (Exception ex){Console.WriteLine("关闭内部读取OPCUA线程异常:" + ex.Message);}try{if (this.myOpcHelper != null){this.myOpcHelper.Close();this.myOpcHelper = null;this.State = false;this._isOpen = false;} }catch (Exception ex){Console.WriteLine("关于与OPCUA服务连接异常:" + ex.Message);} }endregionregion 辅助方法/// <summary>/// 获取某个数据块标签的最小开始索引/// </summary>/// <param name="block">块号</param>/// <returns>返回数据块标签的最小开始索引</returns>private int GetExistsMinBeginByBlock(string block){int existsMinBegin = 99999; //已存在标签的最小开始索引int existsMaxEnd = 0; //已存在标签的最大结束索引bool isContinue = true; //标签值是否连续string[] existsTags = this.readResult.Keys.ToArray<string>();string[] beginend = null;bool parseResult = false;int begin = 0;int end = 0;foreach (string tag in existsTags){if (tag.StartsWith(String.Format("{0}{1}.", groupNamePrefix, block)) && tag.Contains(".") && tag.Contains("-")){string[] tagname = tag.Split(new char[] { '.' });if (tagname.Length == 2){beginend = tagname[1].Split(new char[] { '-' });if (beginend.Length == 2){parseResult = int.TryParse(beginend[0], out begin);if (parseResult){parseResult = int.TryParse(beginend[1], out end);}region 计算最小开始索引和最大结束索引if (begin < existsMinBegin){existsMinBegin = begin;region 判断标签值是否连续if (existsMaxEnd != 0 && begin != existsMaxEnd + 1){isContinue = false;}endregion}if (end > existsMaxEnd){existsMaxEnd = end;}endregion} }if (parseResult){//} }}return existsMinBegin;}/// <summary>/// 读取标签/// </summary>/// <param name="tagName"></param>private void ReadTag(string tagName){UInt16[] buff = null;if (this.dicTags.ContainsKey(tagName)){if (this.myOpcHelper.ReadUInt16(this.dicTags[tagName], out buff)){//Console.WriteLine("tagName={0}, buff length = {1}", tagName, buff.Length);if (this.readResult.ContainsKey(tagName)){this.readResult[tagName] = buff;}else{this.readResult.Add(tagName, buff);} }else{Console.WriteLine("Mesnac.Equip.OPC.OpcUa.OPCUA.Equip.ReadTag Exception 读取标签:[{0}]失败!", tagName);} }else{Console.WriteLine("Mesnac.Equip.OPC.OpcUa.OPCUA.Equip.ReadTag Exception OPCUA Server中未定义此标签:[{0}]!", tagName);} }/// <summary>/// 内部自动读取方法/// </summary>private void InnerAutoRead(){while (this._isOpen && this._isClosing == false){try{if (this.myOpcHelper == null){this._isClosing = true;this.State = false;return;}lock (this){string[] keys = this.readResult.Keys.ToArray<string>();foreach (string key in keys){this.ReadTag(key);} }System.Threading.Thread.Sleep(this.innerReadRate);}catch (Exception ex){Console.WriteLine("Mesnac.Equip.OPC.OpcUa.OPCUA.Equip.InnerAutoRead Exception : " + ex.Message);} }this.innerReadThread = null;}endregionregion 析构方法~Equip(){this.Close();}endregion} } 代码下载 代码下载 本篇文章为转载内容。原文链接:https://blog.csdn.net/zlbdmm/article/details/96714776。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-05-10 18:43:00
269
转载
转载文章
...以不用再踩。 “提出问题”难于“解决问题” 作为技术人员,我们已经习惯于作为问题的解决者给出设计方案,而很少以问题提出者的身份去思考设计方案。团队中常见的典型矛盾,就是产品团队和研发团队之间的矛盾。作为研发团队,我们常吐槽产品团队的需求不合理、不懂技术等。其实我们可以试着把自己的工作再往前移一下,不仅仅是去设计架构、实现产品的需求,同时也试着去实现客户的需求,甚至发现潜在的需求。 这时我们就变成了在设计上提出问题的人,你会发现提出问题的同时,在很多时候也需要同样深入的思考。设计一个好的问题,甚至比解决问题更难。 其实即便是软件开发领域的大神 Frederick P. Brooks Jr.(《人月神话》的作者)也会有同样的感叹。 “The hardest part of design is deciding what to design.” – 《The design of design》, by Frederick P. Brooks Jr. 决定“不要什么”比“要什么”更难 也许是由于人性的贪婪,对于软件系统我们同样想要更多:更多功能、更好的性能、更好的伸缩性、扩展性等等。作为软件架构师要明白软件架构设计就是一种取舍或平衡。当大家都在往里面加东西的时候,架构师更应该来做这个说“不”的人。 软件设计和定义过程中存在很多取舍,例如: 完善功能和尽早发布的取舍。 伸缩性和性能的取舍。 著名的 CAP 原则,就是一个很好的取舍指导策略。为了更好的取舍,保持架构风格的一致性,在一开始架构师就应该根据系统的实际需求来定义一些取舍的原则,如: 数据一致性拥有最高优先级。 提前发布核心功能优于完整发布等。 非功能性需求决定架构 因为软件是为了满足客户的功能性需求的,所以很多设计人员可能会认为架构是由要实现的功能性需求决定的。但实际上真正决定软件架构的其实是非功能性需求。 架构师要更加关注非功能性需求,常见的非功能性包括:性能,伸缩性,扩展性和可维护性等,甚至还包括团队技术水平和发布时间要求。能实现功能的设计总是有很多,考虑了非功能性需求后才能筛选出最合适的设计。 以上架构模式来自《面向模式的软件架构》的第一卷,这套书多年来一直是架构师的必读经典。面向架构的模式就是为不同的非功能性需求提供了很好的参考和指导。图中的 Micro-Kernel 模式,更加关注可扩展性和可用性(错误隔离)。 “简单”并不“容易” 很多架构师都会常常提到保持简单,但是有时候我们会混淆简单和容易。简单和容易在英语里也是两个词“simple”和“easy”。 “Simple can be harder than complex: You have to work hard to get your thinking clean to make it simple. But it’s worth it in the end because once you get there, you can move mountains. To be truly simple, you have to go really deep.” –SteveJobs 真正的一些简单的方法其实来自于对问题和技术更深入的理解。这些方案往往不是容易获得的、表面上的方法。简单可以说蕴含着一种深入的技巧在其中。 下面我来举一个例子。 首先我们来回顾一下软件生命周期中各个阶段的成本消耗占比。以下是来一个知名统计机构的分析报告。我们可以看到占比最大的是维护部分,对于这一部分的简化将最具有全局意义。 我曾经开发过一个设备管理系统,移动运营商通过这个系统来管理移动设备,实现包括设备的自动注册、固件和软件的同步等管理功能。这些功能是通过一些管理系统与移动设备间的预定义的交互协议来完成的。 电信专家们会根据业务场景及需求来调整和新增这些交互协议。起初我们采用了一种容易实现的方式,即团队中的软件工程会根据电信专家的说明,将协议实现为对应代码。 之后我们很快发现这样的方式,让我们的工作变得没那么简单。 “I believe that the hardest part of software projects, the most common source of project failure, is communication with the customers and users of that software.” –Martin Fowler 正如软件开发大师 MartinFowler 提到的,“沟通”往往是导致软件项目失败的主要原因。前面这个项目最大的问题是在系统上线后的运行维护阶段,电信专家和开发工程师之间会不断就新的协议修改和增加进行持续的沟通,而他们的领域知识和词汇都有很大的差别,这会大大影响沟通的效率。因此这期间系统的运行维护(协议的修改)变得十分艰难,不仅协议更新上线时间慢,而且由于软件工程对于电信协议理解程度有限,很多问题都要在实际上线使用后才能被电信专家发现,导致了很多的交换和反复。 针对上面提到的问题,后来我们和电信专家一起设计了一种协议设计语言(并提供可视化的工具),这种设计语言使用的电信专家所熟悉的词汇。然后通过一个类似于编译器的程序将电信专家定义好的协议模型转换为内存中的 Java 结构。这样整个项目的运行和维护就变得简单高效了,省去了低效的交流和不准确人工转换。 我们可以看到一开始按电信专家的说明直接实现协议是更为容易的办法,但就整个软件生命周期来看却并不是一个简单高效的方法。 永远不要停止编码 架构师也是程序员,代码是软件的最终实现形态,停止编程会逐渐让你忘记作为程序员的感受,更重要的是忘记其中的“痛”,从而容易产生一些不切实际的设计。 大家可能听说过在 Amazon,高级副总裁级别的 Distinguish Engineer(如:James Gosling,Java 之父),他们每年的编码量也非常大,常在 10 万行以上。 风险优先 架构设计很重要的一点是识别可能存在的风险,尤其是非功能性需求实现的风险。因为这些风险往往没有功能性需求这么容易在初期被发现,但修正的代价通常要比修正功能性需求大非常多,甚至可能导致项目的失败,前面我们也提到了非功能性需求决定了架构,如数据一致性要求、响应延迟要求等。 我们应该通过原型或在早期的迭代中确认风险能够通过合理的架构得以解决。 绝对不要把风险放到最后,就算是一个项目要失败也要让它快速失败,这也是一种敏捷。 从“问题”开始,而不是“技术” 技术人员对于新技术的都有着一种与身俱来的激情,总是乐于去学习新技术,同时也更有激情去使用新技术。但是这也同样容易导致一个通病,就是“当我们有一个锤子的时候看什么都是钉子”,使用一些不适合的技术去解决手边的问题,常常会导致简单问题复杂化。 我曾经的一个团队维护过这样一个简单的服务,起初就是一个用 MySQL 作数据存储的简单服务,由团队的一个成员来开发和维护。后来,这位成员对当时新出的 DynamoDB 产生了兴趣,并学习了相关知识。 然后就发生下面这样的事: 用DynamoDB替换了MySQL。 很快发现DynamoDB并不能很好的支持事务特性,在当时只有一个性能极差的客户端类库来支持事物,由于采用客户端方式,引入了大量的额外交互,导致性能差别达7倍之多。这时候,这个同学就采用了当时在NoSQL领域广泛流行的最终一致技术,通过一个Pub-Sub消息队列来实现最终一致(即当某对象的值发生改变后会产生一个事件,然后关注这一改变的逻辑,就会订阅这个通知,并改变于其相关数据,从而实现不同数据的最终一致)。 接着由于DynamoDB无法提供SQL那样方便的查询机制,为了实现数据分析就又引入了EMR/MapReduceJob。 到此,大家可以看到实现一样的功能,但是复杂性大大增加,维护工作也由一个人变成了一个团队。 过度忙碌使你落后 对于 IT 人而言忙碌已成为了习惯,加班常挂在嘴边。“996”工作制似乎也变成了公司高效的标志。而事实上过度的忙碌使你落后。经常遇见一些朋友,在一个公司没日没夜的干了几年,没有留一点学习时间给自己。几年之后倒是对公司越来越“忠诚”了,但忙碌的工作同时也导致了没有时间更新知识,使得自己已经落后了,连跳槽的能力和勇气都失去了。 过度忙碌会导致没有时间学习和更新自己的知识,尤其在这个高速发展的时代。我在工作经历中发现过度繁忙通常会带来以下问题: 缺乏学习导致工作能力没有提升,而面对的问题却变得日益复杂。 技术和业务上没有更大的领先优势,只能被动紧紧追赶。试想一下,要是你都领先同行业五年了,还会在乎通过加班来早一个月发布吗? 反过来上面这些问题会导致你更加繁忙,进而更没有时间提高自己的技术技能,很快就形成了一个恶性循环。 练过健身的朋友都知道,光靠锻炼是不行的,营养补充和锻炼同样重要。个人技术成长其实也一样,实践和学习是一样重要的,当你在一个领域工作了一段时间以后,工作对你而言就主要是实践了,随着你对该领域的熟悉,能学习的到技术会越来越少。所以每个技术人员都要保证充足的学习时间,否则很容易成为井底之蛙,从而陷入前面提到的恶性循环。 最后,以伟大诗人屈原的诗句和大家共勉:“路漫漫其修远兮,吾将上下而求索“。希望我们大家都可以不忘初心,保持匠心! 作者简介: 蔡超,Mobvista 技术 VP 兼首席架构师,SpotMax 云服务创始人。拥有超过 15 年的软件开发经验,其中 9 年任世界级 IT 公司软件架构师/首席软件架构师。2017 年加入 Mobvista,任公司技术副总裁及首席架构师,领导公司的数字移动营销平台的开发,该平台完全建立于云计算技术之上,每天处理来自全球不同 region 的超过 600 亿次的请求。 在加入 Mobvista 之前,曾任亚马逊全球直运平台首席架构师,亚马逊(中国)首席架构师,曾领导了亚马逊的全球直运平台的开发,并领导中国团队通过 AI 及云计算技术为中国客户打造更好的本地体验;曾任 HP(中国)移动设备管理系统首席软件架构师,该系统曾是全球最大的无线设备管理系统(OMA DM)(客户包括中国移动,中国联通,中国电信等);曾任北京天融信网络安全技术公司,首席软件架构师,领导开发的网络安全管理系统(TopAnalyzer)至今仍被政府重要部门及军队广为采用,该系统也曾成功应用于 2008 北京奥运,2010 上海世博等重要事件的网络安全防护。 本篇文章为转载内容。原文链接:https://blog.csdn.net/Honnyee/article/details/111896981。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-09-19 14:55:26
78
转载
转载文章
...中年职场转型与再发展问题,报道指出,在数字化时代背景下,中年人应主动拥抱变化,通过不断学习新技术、新知识,更新自身技能树,并积极参与职业培训和继续教育,拓宽职业发展空间。 此外,据LinkedIn(领英)发布的《中国人才趋势报告》显示,企业对具备跨界能力、持续学习力以及深厚行业经验的中高级人才需求不减反增。这进一步印证了文章中的观点:无论年龄大小,职场人士都需要设立明确目标,增强执行力,并懂得投资自己,通过不断学习实现职业生涯的可持续发展。 同时,心理学专家也强调,保持积极心态是中年人应对职场挑战的关键要素之一。正如美国心理学家卡罗尔·德韦克提出的“成长思维模式”,鼓励人们以开放的态度看待困难和挑战,相信能力可以通过努力得以提升,这对于中年职场人士打破现状、激发潜力具有深远意义。 综上所述,面对日新月异的社会变迁和职场环境,中年群体需树立长期职业规划意识,提高实际行动力,强化个人核心竞争力,并始终保持与时俱进的学习态度和积极进取的心态,以此来应对职业道路上的各种挑战,实现职业生涯的二次腾飞。
2023-06-29 14:16:29
119
转载
转载文章
...在碎片化、不可进化的问题,也无法达到公有云启用便捷、功能不断进化、统一运维、按需付费的消费级体验,成为传统私有云规模化增长的掣肘。 当然,过去几年国内外公有云巨头也纷纷推出面向私有云市场的专有云产品,但其设计思路是以公有云为核心,其价值更多在于公有云服务在防火墙内的延伸,其初衷是“将数据迁移到中心云上”,这同样不适合,更难以匹配中国企业希望“将云移动到数据上”的最终目标。 正是源于这些客户“痛点”和市场现状,让华云数据产生了打造一款通用型云操作系统的想法。今年3月1日,华云数据宣布对超融合软件厂商Maxta全部资产完成了合法合规收购。至此,华云数据将独家拥有Maxta的包括产品技术、专利软著、品牌、市场在内的全球范围的资产所有权。 在此基础上,华云数据又把Maxta与华云自身的优势产品相融合,正式推出了安超OS国产通用型云操作系统,并在国产化与通用型方向做了三个方面的重要演进: 首先,兼容国产服务器、CPU、操作系统。安超OS对代码进行了全新的架构扩展,创建并维护新的一套代码分支,从源码级完成众多底层的对国产服务器、CPU、操作系统的支持。 其次,扩展通用型云操作系统的易用性。安超OS以VM为核心做为管理理念,以业务应用的视觉管理基础设施,为云操作系统开发了生命周期管理系统(LCM),提供像服务器操作系统的光盘ISO安装方式,可以30分钟完成云操作系统的搭建,并具备一键集群启停、一键日志收集、一键运维巡检业务等通用型云操作系统所必备的易用性功能。 最后,增强国内行业、企业所需的安全性。安超OS的所有源代码都通过了相关部门的安全检查,确保没有“后门”等漏洞,杜绝安全隐患,并且通过了由中国数据中心联盟、云计算开源产业联盟组织,中国信息通信研究院(工信部电信研究院)测试评估的可信云认证。 不难看出,安超OS不仅具有全球领先的技术,同时又充分满足中国市场和中国客户的需求。正如华云数据集团董事长、总裁许广彬所言:“唯改革者进,唯创新者强,华云数据愿意用全球视野推动中国云计算发展,用云创新驱动数字经济挺进新纵深,植根中国,奉献中国,引领中国,腾飞中国。” 五大维度解读安超OS 那么,什么是云操作系统?安超OS通用型云操作系统又有什么与众不同之处呢? 华云数据集团联席总裁、首席技术官谭瑞忠 在华云数据集团联席总裁、首席技术官谭瑞忠看来,云操作系统是基于服务器操作系统,高度的融合了基础设施的资源,实现了资源弹性伸缩扩展,以及具备运维自动化智能化等云计算的特点。同时,云操作系统具有和计算机操作系统一样的高稳定性,高性能,高易用性等特征。 但是,相比计算机操作系统,云计算的操作系统会更为复杂,属于云计算后台数据中心的整体管理运营系统,是构架于服务器、存储、网络等基础硬件资源和PC操作系统、中间件、数据库等基础软件之上的、管理海量的基础硬件、软件资源的云平台综合管理系统。 更为关键的是,和国内外很多基础设备厂商基于自已的产品与理解推出了云操作系统不同,安超OS走的是通用型云操作系统的技术路线,它不是采用软硬件一体的封闭或半封闭的云操作系统平台,所以这也让安超OS拥有安全稳定、广泛兼容、业务优化、简洁运维、高性价比方面的特性,具体而言: 一是,在安全稳定方面,安超OS采用全容错架构设计,从数据一致性校验到磁盘损坏,从节点故障到区域性灾难,提供端到端的容错和灾备方案,为企业构筑高可用的通用型云环境,为企业的业务运营提供坚实与安全可靠的基础平台。 二是,在广泛兼容方面,安超OS所有产品技术、专利软著、品牌都拥有国内自主权,符合国家相关安全自主可信的规范要求,无服务器硬件锁定,支持国内外主流品牌服务器,同时适配大多数芯片、操作系统和中间件,支持利旧与升级,更新硬件时无需重新购买软件,为企业客户提供显著的投资保护,降低企业IT成本。 三是,在业务优化方面,安超OS具备在同一集群内提供混合业务负载的独特能力,可在一套安超OS环境内实现不同业务的优化:为每类应用定制不同的存储数据块大小,优化应用读写效率,提供更高的业务性能;数据可按组织架构逻辑隔离,部门拥有独立的副本而无需新建一套云环境,降低企业IT的成本与复杂度;数据重构优先级保证关键业务在故障时第一时间恢复,也能避免业务链启动错误的场景出现。 四是,在简捷运维方面,安超OS是一款轻量级云创新平台,其所有管理策略以虚拟机和业务为核心,不需要配置或管理卷、LUN、文件系统、RAID等需求,从根本上简化了云操作系统的管理。通过标准ISO安装,可实现30分钟平台极速搭建,1分钟业务快速部署,一键集群启停与一键运维巡检。降低企业IT技术门槛,使IT部门从技术转移并聚焦于业务推进和变革,助力企业实现软件定义数据中心。 五是,在高性价比方面,安超OS在设计之初,华云数据就考虑到它是一个小而美、大而全的产品,所以给客户提供组件化授权,方便用户按需购买,按需使用,避免一次性采购过度,产生配置浪费。并且安超OS提供在线压缩等容量优化方案,支持无限个数无损快照,无硬件绑定,支持License迁移。 由此可见,安超OS通用型云操作系统的本质,其实就是一款以安全可信为基础,以业务优化为核心的轻量级云创新平台,能够让中国政府和企业在数字化转型中,更好的发挥云平台的价值,同时也能有效的支持他们的业务创新。 生态之上的云操作系统 纵观IT发展的过程,每个时代都离不开通用型操作系统:在PC时代,通用型操作系统是Windows、Linux;在移动互联时代,通用型操作系统是安卓(Android),而这些通用型操作系统之所以能够成功,背后其实也离不开生态的开放和壮大。 如果以此类比的话,生态合作和生态开放同样也是华云安超OS产品的核心战略,这也让安超OS超越了传统意义上的云创新平台,是一款架构于生态开放之上的云操作系统。 华云数据集团副董事长、执行副总裁马杜 据华云数据集团副董事长、执行副总裁马杜介绍,目前华云数据正与业内众多合作伙伴建立了生态合作关系,覆盖硬件、软件、芯片、应用、方案等多个领域,通过生态合作,华云数据希望进一步完善云数据中心的产业链生态,与合作伙伴共建云计算生态圈。 其中,在基础架构方面,华云数据与飞腾、海光、申威等芯片厂商以及中标麒麟、银河麒麟等国产操作系统实现了互认证,与VMware、Dell EMC、广达、浪潮、曙光、长城、Citrix、Veeam、SevOne、XSKY、锐捷网络、上海仪电、NEXIFY等多家国内外知名IT厂商达成了战略合作,共同为中国政企用户提供基于云计算的通用行业解决方案与垂直行业解决方案,助推用户上云实现创新加速模式。 同时,在解决方案方面,华云数据也一直在完善自身的产业链,建立最广泛的生态体系。例如,PaaS平台领域的合作伙伴包括灵雀云、Daocloud、时速云、优创联动、长城超云、蓝云、星环科技、华夏博格、时汇信息、云赛、热璞科技、思捷、和信创天、酷站科技、至臻科技达成合作关系;数据备份领域有金蝶、爱数、Veeam、英方云、壹进制;安全领域有亚信安全、江南安全、绿盟、赛亚安全、默安科技;行业厂商包括善智互联、蓝美视讯、滴滴、天港集团、航天科工等合作伙伴,由此形成了非常有竞争力的整体解决方案。 不仅如此,华云数据与众多生态厂家共同完成了兼容性互认证测试,构建了一个最全面的基础架构生态体系,为推出的国产通用型云操作系统提供了一个坚实的基础。也让该系统提高了其包括架构优化能力、技术研发能力、资源整合能力、海量运营能力在内的综合能力,为客户提供稳定、可靠的上云服务,赋能产业变革。 值得一提的是,华云数据还发布了让利于合作伙伴的渠道合作策略,通过和合作伙伴的合作共赢,华云数据希望将安超OS推广到国内的全行业,让中国企业都能用上安全、放心的国产通用型云操作系统,并让安超OS真正成为未来中国企业上云的重要推手。 显而易见,数字化的转型与升级,以及数字经济的落地和发展,任重而道远,艰难而伟大,而华云数据正以安超OS云操作系统为核心构建的新生态模式和所释放的新能力,不仅会驱动华云数据未来展现出更多的可能性,激发出更多新的升维竞争力,更将会加速整个中国政府和企业的数字化转型步伐。 全文总结,在云计算落地中国的过程中,华云数据既是早期的探索者,也是落地的实践者,更是未来的推动者。特别是安超OS云操作系统的推出,背后正是华云凭借较强的技术驾驭能力,以及对中国企业用户痛点的捕捉,使得华云能够走出一条差异化的创新成长之路,也真正重新定义了“中国云”未来的发展壮大之路。 申耀的科技观察,由科技与汽车跨界媒体人申斯基(微信号:shenyao)创办,16年媒体工作经验,拥有中美两地16万公里自驾经验,专注产业互联网、企业数字化、渠道生态以及汽车科技内容的观察和思考。 本篇文章为转载内容。原文链接:https://blog.csdn.net/W5AeN4Hhx17EDo1/article/details/99899011。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-03-16 21:41:38
302
转载
站内搜索
用于搜索本网站内部文章,支持栏目切换。
知识学习
实践的时候请根据实际情况谨慎操作。
随机学习一条linux命令:
ncurses-based tools (例如:top, htop)
- 监控系统资源如CPU、内存等。
推荐内容
推荐本栏目内的其它文章,看看还有哪些文章让你感兴趣。
2023-04-28
2023-08-09
2023-06-18
2023-04-14
2023-02-18
2023-04-17
2024-01-11
2023-10-03
2023-09-09
2023-06-13
2023-08-07
2023-03-11
历史内容
快速导航到对应月份的历史文章列表。
随便看看
拉到页底了吧,随便看看还有哪些文章你可能感兴趣。
时光飞逝
"流光容易把人抛,红了樱桃,绿了芭蕉。"