首页
小游戏
壁纸
留言
视频
友链
关于
Search
1
上海市第八人民医院核酸检测攻略(时间+预约+报告)-上海
299 阅读
2
上海烟花销售点一览表2022-上海
241 阅读
3
新款的 Thinkbook 16+ 值不值得买?-知乎热搜
219 阅读
4
如何看待网传小米 MIUI 13 内置国家反诈中心 APP?-知乎热搜
214 阅读
5
窦唯到底厉害在哪里?-知乎热搜
192 阅读
免费代理IP
免费翻墙节点
文章聚合
掘金
知乎
IT之家
本地宝
观察者网
金山词霸
搜韵网
新华网
其他
登录
/
注册
Search
标签搜索
知乎热搜
IT之家热榜
广州
深圳
北京
观察者网头条
前端
上海
后端
知乎日报
Android
iOS
人工智能
阅读
工具资源
杭州
诗词日历
每日一句
郑州
设计
看啥
累计撰写
129,720
篇文章
累计收到
46
条评论
首页
栏目
免费代理IP
免费翻墙节点
文章聚合
掘金
知乎
IT之家
本地宝
观察者网
金山词霸
搜韵网
新华网
其他
页面
小游戏
壁纸
留言
视频
友链
关于
搜索到
1285
篇与
的结果
2022-10-19
Scoop: Windows下的包管理器-掘金
作为程序员,换电脑的时候重新配置环境应该是很痛苦的,尤其是在 Windows 上,需要访问一堆网站,下载安装程序,然后点击GUI向导的安装程序安装。尤其是用过 homebrew 或者 apt-get 之后,希望有一种更简单的方法来告诉开发人员如何安装程序。Scoop 是个不错的选择。Scoop 是一个 Windows 下的命令行下载工具。Scoop 能做什么?Scoop 能以最小的代价从命令行安装程序。它能 消除权限弹出窗口 隐藏 GUI 向导样式的安装程序 防止 PATH 污染安装大量程序 避免安装和卸载程序的意外副作用 自动查找并安装依赖项 自行执行所有额外的设置步骤以获得工作程序 Scoop 能让程序员留在命令行上,提高效率,而且扩展了 PowerShell,可以使用能够很好处理文本的程序。安装 Scoop从非管理员 PowerShell 运行以下命令,将 scoop 安装到其默认位置。 C:Usersscoopiwr -useb get.scoop.sh | iex 先决条件启用 PowerShell 的执行策略Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser 高级安装如果要进行高级安装,可以下载安装程序并使用参数手动执行它。irm get.scoop.sh -outfile 'install.ps1' 这里可以查看安装程序的所有可配置参数。.install.ps1 -? 例如,将 scoop 安装到自定义目录,将 scoop 配置为将全局程序安装到自定义目录,并在安装时绕过系统代理。.install.ps1 -ScoopDir 'D:Scoop' -ScoopGlobalDir 'F:GlobalScoopApps' -NoProxy 认识 ScoopScoop 安装完成后,可以使用 scoop help 获取帮助信息,可以发现 Scoop 有很多命令选项。简洁易懂,例如,下载一个应用程序 7zipscoop install 7zip 只需要静静等待安装完成即可,完成安装可能需要重启终端,Scoop 会自动完成环境变量的配置,即可使用。那 Scoop 是怎么完成环境变量的配置的呢,我们打开系统环境变量 PATH ,可以发现 Scoop 添加了一个 /shims 变量,打开 Scoop 安装路径下的 shims 可以发现目录下有安装软件的可执行文件和同名的 .shim 文件,.shim 里的内容指向实际程序路径。卸载程序也很简单scoop uninstall 7zip 如果需要升级应用程序或者 Scoop 本身,只需要使用 scoop update 命令,详细信息可以加上参数 --help 获取。安装应用大概了解了 Scoop 的使用,就可以安装应用了。但是在这之前,我们还需要了解一下 Scoop 的存储桶机制,Scoop 使用存储桶来存储应用。存储桶以下是 Scoop 已知的存储桶: main - 最常见(主要是CLI)应用的默认存储桶 extras - 不符合主存储桶条件的应用 games - 开源/免费软件游戏和游戏相关工具 nerd-fonts - 字体 nirsoft - Nirsoft 的几乎所有250多个应用程序 java - Java 开发工具包 (JDK)、Java 运行时引擎 (JRE)、Java 的虚拟机调试工具和基于 Java 的运行时引擎的集合。 nonportable - 非便携式应用(可能需要 UAC) php - 大多数版本的 PHP 的安装程序 versions - 在其他存储桶中找到的应用程序的替代版本 默认情况下会安装主存储桶。要添加任何其他存储桶,可以自行添加scoop bucket add bucketname 例如,要添加附加存储桶,请键入:scoop bucket add extras Github上托管的许多其他应用程序存储桶可以在Scoop 目录或其他搜索引擎中找到。必备应用这里是个人建议,非常好用的应用 main/sudo: 模拟 UNIX 环境下 sudo 命令,在命令前使用 sudo 命令会弹出提升至管理员权限的窗口。 main/touch: 同样是模拟 UNIX 环境下的 touch 命令 main/aria2: 使用多连接下载 默认情况下,在运行时或启用时显示警告。可以通过运行命令来抑制此警告。scoop config aria2-warning-enabled false 常用软件像是 git, vscode 这样的软件都可以通过 Scoop 安装,推荐使用这个网站:Scoop,可以找到大部分开发软件所在的存储桶,安装命令可以直接复制到命令行。Scoop 可以安装什么样的应用程序?使用 Scoop 安装最好的应用程序通常被称为“便携式”应用程序:即压缩的程序文件,它们在提取时独立运行,并且没有副作用,例如更改注册表或将文件放在程序目录之外。由于安装程序很常见,因此 Scoop 也支持它们(及其卸载程序)。但是对于 TIM,腾讯会议之类的应用,可能 Scoop 支持的不多,就得去官网下载了。社区存储桶的 star 数或许能做个参考,数量太少很容易失效,毕竟是个人维护,建议使用尽量使用官方的存储桶。导出安装的应用换电脑怎么办?总不能再一个个命令敲进去安装应用吧?别急,Scoop 提供了导出选项,将安装的存储桶和应用全部导出为配置文件,下次安装的时候直接导入即可。导出:scoop export > scoopfile.json 导出的 JSON 文件:{ "buckets": [ { "Name": "main", "Source": "https://github.com/ScoopInstaller/Main", "Updated": { "value": "/Date(1661805004000)/", "DisplayHint": 2, "DateTime": "2022年8月30日 4:30:04" }, "Manifests": 1072 }, { "Name": "versions", "Source": "https://github.com/ScoopInstaller/Versions", "Updated": { "value": "/Date(1662064635000)/", "DisplayHint": 2, "DateTime": "2022年9月2日 4:37:15" }, "Manifests": 354 }, ... ], "apps": [ { "Info": "", "Source": "main", "Name": "7zip", "Version": "22.01", "Updated": "/Date(1659095893850)/" }, { "Info": "", "Source": "main", "Name": "aria2", "Version": "1.36.0-1", "Updated": "/Date(1657286226200)/" }, ... ] } 导入同样简单scoop import 以上文章来自[掘金]-[wlonestar]本程序使用github开源项目RSSHub提取聚合!
2022年10月19日
0 阅读
0 评论
0 点赞
2022-10-19
Java 19 发布,Loom 怎么解决 Java 的并发模型缺陷?丨未来源码-掘金
本文来自InfoQ 中文站,原作者 Deepu K Sasidharan。推荐语:对于我们开发的网站,如果访问量太大,请求激增,就需要考虑相关的并发问题。异步并发,意味着要适应更复杂的编程风格。Java中的传统线程非常繁重,并且与操作系统线程一对一绑定。而Loom是jave生态里一个较新的项目,它试图解决传统并发模型中的限制。但具体怎么实现,本文做了详细的说明。随着Project Loom的进入,也许未来,java生态系统的性能将发生数量级提升的天翻地覆的变化。—— MobTech袤博科技资深java开发工程师 零零发Java 19已经于日前发布,其中最引人注目的特性就要数虚拟线程了,本文介绍了 Loom 项目中虚拟线程和结构化编程的基础知识,并将其与操作系统线程进行了对比分析。Java 在其发展早期就具有良好的多线程和并发能力,能够高效地利用多线程和多核 CPU。Java 开发工具包(Java Development Kit,JDK)1.1 对平台线程(或操作系统(OS)线程)提供了基本的支持,JDK 1.5 提供了更多的实用工具和更新,以改善并发和多线程。JDK 8 带来了异步编程支持和更多的并发改善。虽然在多个不同的版本中都进行了改进,但在过去三十多年中,除了基于操作系统的并发和多线程支持之外,Java 并没有任何突破性的进展。尽管 Java 中的并发模型非常强大和灵活,但它并不是最易于使用的,而且开发人员的体验也不是很好。这主要是因为它默认使用的共享状态并发模型。我们必须借助同步线程来避免数据竞争(data race)和线程阻塞这样的问题。我曾经在一篇名为“现代编程语言中的并发:Java”的博客文章中讨论过 Java 并发问题。Loom 项目是什么?Loom 项目致力于大幅减少编写、维护和观察高吞吐量并发应用相关的工作,以最佳的方式利用现有的硬件。——Ron Pressler(Loom 项目的技术负责人)操作系统线程是 Java 并发模型的核心,围绕它们有一个非常成熟的生态系统,但是它们也有一些缺点,如计算方式很昂贵。我们来看一下并发的两个最常见使用场景,以及当前的 Java 并发模型在这些场景下的缺点。最常见的并发使用场景之一就是借助服务器在网络上为请求提供服务。在这样的场景中,首选的方法是“每个请求一个线程(thread-per-request)”模型,即由一个单独的线程处理每个请求。这种系统的吞吐量可以用Little定律来计算,该定律指出,在一个稳定的系统中,平均并发量(服务器并发处理的请求数)L 等于吞吐量(请求的平均速率)λ乘以延迟(处理每个请求的平均时间)W。基于此,我们可以得出,吞吐量等于平均并发除以延迟(λ = L/W)。因此,在“每个请求一个线程”模型中,吞吐量将受到操作系统线程数量的限制,这取决于硬件上可用的物理核心/线程数。为了解决这个问题,我们必须使用共享线程池或异步并发,这两种方法各有缺点。线程池有很多限制,如线程泄漏、死锁、资源激增等。异步并发意味着必须要适应更复杂的编程风格,并谨慎处理数据竞争。它们还有可能出现内存泄漏、线程锁定等问题。另一个常见的使用场景是并行处理或多线程,我们可能会把一个任务分成跨多个线程的子任务。此时,我们必须编写避免数据损坏和数据竞争的解决方案。在有些情况下,当执行分布在多个线程上的并行任务时,还必须要确保线程同步。这种实现会非常脆弱,并且将大量的责任推给了开发人员,以确保没有像线程泄露和取消延迟这样的问题。Loom 项目旨在通过引入两个新特性来解决当前并发模型中的这些问题,即虚拟线程(virtual thread)和结构化并发(structured concurrency)。虚拟线程Java 19 已经于 2022 年 9 月 20 日发布,虚拟线程是其中的一项预览功能。虚拟线程是轻量级的线程,它们不与操作系统线程绑定,而是由 JVM 来管理。它们适用于“每个请求一个线程”的编程风格,同时没有操作系统线程的限制。我们能够创建数以百万计的虚拟线程而不会影响吞吐。这与 Go 编程语言(Golang)的协程(如goroutines)非常相似。Java 19 中的虚拟线程新特性很易于使用。在这里,我将其与 Golang 的 goroutines 以及 Kotlin 的 coroutines 进行了对比。虚拟线程Thread.startVirtualThread(() -> { System.out.println("Hello, Project Loom!");}); Goroutinego func() { println("Hello, Goroutines!")}() Kotlin coroutinerunBlocking { launch { println("Hello, Kotlin coroutines!") }} 冷知识:在 JDK 1.1 之前,Java 曾经支持过绿色线程(又称虚拟线程),但该功能在 JDK 1.1 中移除了,因为当时该实现并没有比平台线程更好。虚拟线程的新实现是在 JVM 中完成的,它将多个虚拟线程映射为一个或多个操作系统线程,开发人员可以按需使用虚拟线程或平台线程。这种虚拟线程实现还有如下几个注意事项: 在代码、运行时、调试器和剖析器(profiler)中,它是一个Thread。 它是一个 Java 实体,并不是对原生线程的封装。 创建和阻塞它们是代价低廉的操作。 它们不应该放到池中。 虚拟线程使用了一个基于任务窃取(work-stealing)的ForkJoinPool调度器。 可以将可插拔的调度器用于异步编程中。 虚拟线程会有自己的栈内存。 虚拟线程的 API 与平台线程非常相似,因此更容易使用或移植。 我们看几个展示虚拟线程威力的样例。线程的总数量首先,我们看一下在一台机器上可以创建多少个平台线程和虚拟线程。我的机器是英特尔酷睿 i9-11900H 处理器,8 个核心、16 个线程、64GB 内存,运行的操作系统是 Fedora 36。平台线程var counter = new AtomicInteger();while (true) { new Thread(() -> { int count = counter.incrementAndGet(); System.out.println("Thread count = " + count); LockSupport.park(); }).start();} 在我的机器上,在创建 32,539 个平台线程后代码就崩溃了。虚拟线程var counter = new AtomicInteger();while (true) { Thread.startVirtualThread(() -> { int count = counter.incrementAndGet(); System.out.println("Thread count = " + count); LockSupport.park(); });} 在我的机器上,进程在创建 14,625,956 个虚拟线程后被挂起,但没有崩溃,随着内存逐渐可用,它一直在缓慢进行。你可能想知道为什么会出现这种情况。这是因为被 park 的虚拟线程会被垃圾回收,JVM 能够创建更多的虚拟线程并将其分配给底层的平台线程。任务吞吐量我们尝试使用平台线程来运行 100,000 个任务。try (var executor = Executors.newThreadPerTaskExecutor(Executors.defaultThreadFactory())) { IntStream.range(0, 100_000).forEach(i -> executor.submit(() -> { Thread.sleep(Duration.ofSeconds(1)); System.out.println(i); return i; }));} 在这里,我们使用了带有默认线程工厂的newThreadPerTaskExecutor方法,因此使用了一个线程组。运行这段代码并计时,我得到了如下的结果。当使用Executors.newCachedThreadPool()线程池时,我得到了更好的性能。# 'newThreadPerTaskExecutor' with 'defaultThreadFactory'0:18.77 real, 18.15 s user, 7.19 s sys, 135% 3891pu, 0 amem, 743584 mmem# 'newCachedThreadPool' with 'defaultThreadFactory'0:11.52 real, 13.21 s user, 4.91 s sys, 157% 6019pu, 0 amem, 2215972 mmem 看着还不错。现在,让我们用虚拟线程完成相同的任务。try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { IntStream.range(0, 100_000).forEach(i -> executor.submit(() -> { Thread.sleep(Duration.ofSeconds(1)); System.out.println(i); return i; }));} 运行这段代码并计时,我得到了如下结果:0:02.62 real, 6.83 s user, 1.46 s sys, 316% 14840pu, 0 amem, 350268 mmem 这比基于平台线程的线程池要好得多。当然,这些都是很简单的使用场景,线程池和虚拟线程的实现都可以进一步优化以获得更好的性能,但这不是这篇文章的重点。用同样的代码运行Java Microbenchmark Harness(JMH),得到的结果如下。可以看到,虚拟线程的性能比平台线程要好很多。# ThroughputBenchmark Mode Cnt Score Error UnitsLoomBenchmark.platformThreadPerTask thrpt 5 0.362 ± 0.079 ops/sLoomBenchmark.platformThreadPool thrpt 5 0.528 ± 0.067 ops/sLoomBenchmark.virtualThreadPerTask thrpt 5 1.843 ± 0.093 ops/s # Average timeBenchmark Mode Cnt Score Error UnitsLoomBenchmark.platformThreadPerTask avgt 5 5.600 ± 0.768 s/opLoomBenchmark.platformThreadPool avgt 5 3.887 ± 0.717 s/opLoomBenchmark.virtualThreadPerTask avgt 5 1.098 ± 0.020 s/op 你可以在 GitHub 上找到该基准测试的源代码。如下是其他几个有价值的虚拟线程基准测试: 在GitHub上,Elliot Barlas 使用 ApacheBench 做的一个有趣的基准测试。 Alexander Zakusylo在 Medium 上使用 Akka actors 的基准测试。 在GitHub上,Colin Cachia 做的 I/O 和非 I/O 任务的 JMH 基准测试。 结构化并发结构化并发是 Java 19 中的一个孵化功能。结构化并发的目的是简化多线程和并行编程。它将在不同线程中运行的多个任务视为一个工作单元,简化了错误处理和任务取消,同时提高了可靠性和可观测性。这有助于避免线程泄漏和取消延迟等问题。作为一个孵化功能,在稳定过程中可能会经历进一步的变更。我们考虑如下这个使用java.util.concurrent.ExecutorService的样例。void handleOrder() throws ExecutionException, InterruptedException { try (var esvc = new ScheduledThreadPoolExecutor(8)) { Future inventory = esvc.submit(() -> updateInventory()); Future order = esvc.submit(() -> updateOrder()); int theInventory = inventory.get(); // Join updateInventory int theOrder = order.get(); // Join updateOrder System.out.println("Inventory " + theInventory + " updated for order " + theOrder); }} 我们希望updateInventory()和updateOrder()这两个子任务能够并发执行。每一个任务都可以独立地成功或失败。理想情况下,如果任何一个子任务失败,handleOrder()方法都应该失败。然而,如果某个子任务发生失败的话,事情就会变得难以预料。 设想一下,updateInventory()失败并抛出了一个异常。那么,handleOrder()方法在调用invent.get()时将会抛出异常。到目前为止,还没有什么大问题,但updateOrder()呢?因为它在自己的线程上运行,所以它可能会成功完成。但是现在我们就有了一个库存和订单不匹配的问题。假设updateOrder()是一个代价高昂的操作。在这种情况下,我们白白浪费了资源,不得不编写某种防护逻辑来撤销对订单所做的更新,因为我们的整体操作已经失败。 假设updateInventory()是一个代价高昂的长时间运行操作,而updateOrder()抛出一个错误。即便updateOrder()抛出了错误,handleOrder()任务依然会在inventory.get()方法上阻塞。理想情况下,我们希望handleOrder()任务在updateOrder()发生故障时取消updateInventory(),这样就不会浪费时间了。 如果执行handleOrder()的线程被中断,那么中断不会被传播到子任务中。在这种情况下,updateInventory()和updateOrder()会泄露并继续在后台运行。 对于这些场景,我们必须小心翼翼地编写变通方案和故障防护措施,把所有的职责推到了开发人员身上。我们可以使用下面的代码,用结构化并发实现同样的功能。void handleOrder() throws ExecutionException, InterruptedException { try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { Future inventory = scope.fork(() -> updateInventory()); Future order = scope.fork(() -> updateOrder()); scope.join(); // Join both forks scope.throwIfFailed(); // ... and propagate errors // Here, both forks have succeeded, so compose their results System.out.println("Inventory " + inventory.resultNow() + " updated for order " + order.resultNow()); }} 与之前使用ExecutorService的样例不同,我们现在使用StructuredTaskScope来实现同样的结果,并将子任务的生命周期限制在词法的作用域内,在本例中,也就是 try-with-resources 语句体内。这段代码更易读,而且意图也很清楚。StructuredTaskScope还自动确保以下行为: 基于短路的错误处理:如果updateInventory()或updateOrder()失败,另一个将被取消,除非它已经完成。这是由ShutdownOnFailure()实现的取消策略来管理的,我们还可以使用其他策略。 取消传播:如果运行handleOrder()的线程在调用join()之前或调用过程中被中断的话,当该线程退出作用域时,两个分支(fork)都会被自动取消。 可观察性:线程转储文件将清楚地显示任务层次,运行updateInventory()和updateOrder()的线程被显示为作用域的子线程。 Loom 项目状况Loom 项目开始于 2017 年,经历了许多变化和提议。虚拟线程最初被称为 fibers,但后来为了避免混淆而重新进行了命名。如今随着 Java 19 的发布,该项目已经交付了上文讨论的两个功能。其中一个是预览状态,另一个是孵化状态。因此,这些特性的稳定化之路应该会更加清晰。这对普通的 Java 开发人员意味着什么?当这些特性生产环境就绪时,应该不会对普通的 Java 开发人员产生太大的影响,因为这些开发人员可能正在使用某些库来处理并发的场景。但是,在一些比较罕见的场景中,比如你可能进行了大量的多线程操作但是没有使用库,那么这些特性就是很有价值的了。虚拟线程可以毫不费力地替代你现在使用的线程池。根据现有的基准测试,在大多数情况下它们都能提高性能和可扩展性。结构化并发有助于简化多线程或并行处理,使其能加健壮,更易于维护。这对 Java 库开发人员意味着什么?当这些特性生产环境就绪时,对于使用线程或并行的库和框架来说,将是一件大事。库作者能够实现巨大的性能和可扩展性提升,同时简化代码库,使其更易维护。大多数使用线程池和平台线程的 Java 项目都能够从切换至虚拟线程的过程中受益,候选项目包括 Tomcat、Undertow 和 Netty 这样的 Java 服务器软件,以及 Spring 和 Micronaut 这样的 Web 框架。我预计大多数 Java web 技术都将从线程池迁移到虚拟线程。Java web 技术和新兴的反应式编程库,如 RxJava 和 Akka,也可以有效地使用结构化并发。但这并不意味着虚拟线程将成为所有问题的解决方案,异步和反应式编程仍然有其适用场景和收益。了解更多关于 Java、多线程和 Loom 项目的信息: On the Performance of User-Mode Threads and Coroutines State of Loom Project Loom: Modern Scalable Concurrency for the Java Platform Thinking About Massive Throughput? Meet Virtual Threads! Does Java 18 finally have a better alternative to JNI? OAuth for Java Developers Cloud Native Java Microservices with JHipster and Istio 以上文章来自[掘金]-[MobTech开发者]本程序使用github开源项目RSSHub提取聚合!
2022年10月19日
0 阅读
0 评论
0 点赞
2022-10-18
浅析智慧医疗如何基于轻量技术打通服务闭环-掘金
持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情假期深入的体验了现有的医院挂号、线上问诊服务,认为还有一些可以从技术方向优化的方面,顺势就深入研究了目前“智慧医疗”的内容,也在这里分享给感兴趣的小伙伴。智慧医疗作为充分应用计算机技术、信息技术建立的新型医疗方式,正随着新一代信息技术的普及和医疗健康领域需求的变化迎来爆发期。在智慧医疗的生态体系建设上,不仅持续推动了医药、医疗、医保和健康产业的发展,也提升了居民健康福祉。智慧医疗已经取得较快发展计算机和信息技术在医疗健康领域的应用,迄今经历了两个大的阶段。第一阶段是20世纪80-90年代,随着电脑逐渐普及和互联网的出现,医疗机构逐步引入信息化操作,对以人工和纸质为核心的传统运作模式进行革新,越来越多的医疗机构开始建立医院信息系统,开启了医疗信息化的探索。第二个时期是进入21世纪后,随着信息技术应用逐步拓展至社会全场景,医疗健康领域进入了全面数字化的新时期。 一方面,医院的信息化逐渐完善,从最初的门诊管理、住院管理、药房管理衍生出多个子系统,医疗机构覆盖面也逐步提升; 另一方面,新一代信息技术的应用,也先后催生了线上远程问诊、互联网医院等多种新模式。1、互联网医疗迅速发展移动互联网技术愈加成熟及新冠疫情的持续影响下,互联网医院和线上远程问诊逐步成为了智慧医疗的重要场景,截至目前,我国的互联网医院已超过1600家,在线医疗网民达2.76亿人,占网民整体的29.4%,并且我国所有三级医院基本都建立了远程诊疗中心,有条件的二级及以下医疗机构也相继开始建立远程诊疗系统。2、医疗信息一体化建设自2018年开始,相关部门先后发布了《关于加快推进电子健康卡普及应用工作的意见》等多项通知,从提升电子健康档案入手,着手电子健康卡的推广,以强化个人健康索引,链接病历和健康档案,于是乎跨越多领域、多层级的信息系统逐步形成。截至2021年10月,电子健康卡已在21个省份2000多家医疗机构试点使用,活跃用户数达到2.6亿人,累计使用人次超过了60亿。但与此同时,在智慧医疗中也凸显出了IT系统架构陈旧、医疗服务能力未整合、多终端协作能力受限三大问题有待深化。智慧医疗典型问题逐渐凸显数字化技术的应用打破了时间和空间的限制,使得居民与医疗机构能够更紧密的联系在一起,居民就医更加便捷,机构服务效率更加高效,让医疗服务水平提升成为可能。但在实际的落地实践中,还存在一些突出问题亟待解决。1、IT系统架构陈旧大多数的医疗IT系统并非一次性建设到位,而是在多个时间期间内按阶段分别建设,并且多个业务信息系统之间较为零散,系统间的业务逻辑并不连贯。特别是遇到线上问诊人数的急速增长,业务体量越来越大,目前的IT系统灵活性较低,很难做到灵活拓展,如若对某个系统进行改造,又可能造成牵一发而动全身。2、医疗服务能力未整合当前,面对居民用户的很多业务都是以分散的小程序甚至 App 进行承载,例如各个医院有自己的挂号小程序、线上问诊小程序、检查报告查阅 App ,零散的分布在各个平台。一方面,对于居民用户来讲,使用操作十分的不友好,需要下载并来回切换 App ;另一方面,对于医疗机构来讲,多个小程序及 App 由于信息系统零散,数据集中管理难度高,加之医疗机构内复杂的业务形态使得多个信息系统甚至难以实现数据的共享协作。3、多终端协作能力受限根据 IEEE 技术专家指出,IoMT(医疗物联网)将保持每年27.2%的强劲增长速度,到2026年,全球市场规模将达到1560亿美元。可以预见到,人工智能问诊、智能穿戴设备等物联网场景会越来越多的应用在医疗行业中,但当前绝大多数医疗网络系统建设时,技术、产品选型方面都没有为 IoMT 的应用扩展做预留,很难实现多终端设备的业务协作连贯性。智慧医疗的破局之术智慧医疗发展至今,经历了从财务为核心到以诊疗为核心的拓展,目前正处于数据集成到数据共享阶段的发展阶段,而在智慧医疗的强劲发展下,多终端、多设备势必会成为未来一段时间内医疗行业发展的长久之策,医疗行业的破局之术也需要紧密结合多终端能力、数据共享等方面进行统筹考虑,真正让技术能够带动民生健康福祉的持续提升。这时前端统一的业务载体就能很好的将医疗机构的 App 、自助设备、穿戴设备、医院大屏等多终端设备和现有的挂号、问诊、健康咨询、分诊和健康追踪等业务服务进行结合。前端统一的业务载体如何选型?最基本的要求需要具备跨设备、跨平台的能力且需要拥有灵活的拓展能力。此外,居民用户、机构员工的操作使用体验也是在此期间需要特别考虑的因素。这里非常推荐“小程序”轻应用形态,一种“无需下载、即用即走”的轻型应用,因为微信小程序、支付宝小程序快速被大众所熟知,其技术成熟性、使用便利性已经受到市场中成千上万企业及数亿用户的认可。衍生出来的「Native + 小程序」混合开发模式能够帮助智慧医疗行业以最轻量化、最灵活化的技术方式,轻松将原有的臃肿信息系统和 App 功能打散,功能模块互相解耦,进而实现模块化开发,同时让手机、电脑、大屏、智能设备等快入拥有可以自控的小程序运行和管理能力,最大程度构建高度灵活安全的 IT 系统、高效整合医疗服务能力、串联医疗机构多终端设备协作场景。1、构建高度灵活安全的 IT 系统具体来讲小程序容器技术能够让原有的臃肿信息系统和 App 功能做到互相解耦,实现模块化开发,并且各业务模块间互不影响,并且使得 App 及硬件设备具备小程序的运行能力。这样的 IT 架构其优势非常明显: 具备跨平台的能力:一套小程序代码可以在 iOS 、Android 、 Linux、Windows、MacOS、麒麟等多端运行; 支持本地缓存,Webview,有丰富的组件与支持库,用户使用体验远超 H5; 能获取更多系统权限,完成更加丰富的产品设计; 可以避免 DOM 泄露; 包尺寸有效减少,节省流量和存储; 支持热更新,让服务不再受发版所限制。 2、高效整合医疗服务能力对于医疗机构而言,使用例如 FinClip 等小程序容器技术则可以兼容微信小程序语法WXML,这样一来医疗机构能够直接将原有分散在微信小程序平台的挂号服务、线上问诊等小程序整合起来上架到自有 App 或智能设备中,让居民用户能够在优质的体验下在一个应用内享受整个服务闭环。对县(区)级、市级、省级医疗主管单位来讲,可以基于小程序容器技术,将健康码、各家医疗机构挂号、线上问诊、病历档案等小程序整合到一个 App 应用内,用户可以在不切换多个 App 的情况下,就能及时查询并享受线上服务。此外,各家医疗机构通过小程序的形式申请上下架业务小程序,主管单位可以及时管控业务流程中的合规风险,及时对风险暴露的小程序进行下架处理。3、串联医疗机构多终端设备协作场景小程序容器高度的适配性,一套代码即可在iOS 、Android 、 Linux、Windows、MacOS、麒麟等多端运行,可以帮助医疗机构的物联网硬件设备拥有小程序运行能力,并实现多物联网设备间的数据联动,如定位功能、语音交互等,也能帮助实现人与物、物与物之间的信息关联、数据采集,实现医院各个业务、应用系统间智能协作。以上是基于自身使用线上问诊等服务和研究分析智慧医疗行业后的一些想法。以上文章来自[掘金]-[Finbird]本程序使用github开源项目RSSHub提取聚合!
2022年10月18日
0 阅读
0 评论
0 点赞
2022-10-18
【项目实战】记录Webpack 4 升级到 5-掘金
为啥要升级 ?构建速度提升(大概4倍 ) + 长效缓存ps:着实是 文章封面 不好找 ~思想0、先清理 不使用的依赖 1、先自动升级 依赖版本 2、build 错误解决 3、新版本 测试一遍 不报错 4、done ! 开始 先清理依赖 sudo npm install -g npm-check npm-check 使用 npm-check-updates 升级 依赖 对新手还行 sudo npm install -g npm-check-updates npm-check-updates ncu -u # 检查 package.json npm install # 安装依赖 当前 package.json 和 之前对比 npm run build 后解决问题1解决 删除 .babelrc 装 eslint npm install eslint 2解决 src index.js 更改为 main.js 3解决 安装 "eslint-plugin-vue": "^4.5.0",4解决 npm install eslint-plugin-vue -uUpgraded eslint-plugin-vue to 9.1.15解决 Solution:The error occurred because the version you are using is deprecated and the updated version does not support ES6 modules. So the program needs to be updated to the latest babel-eslint-parser.To update to latest babel-eslint-parser you have to follow the below steps: In package.json, update the line "babel-eslint": "^10.0.2", to "@babel/eslint-parser": "^7.5.4",. This works with the code above but it may be better to use the latest version. Run npm i from a terminal in the folder In .eslintrc, update the parser line "parser": "babel-eslint", to "parser": "@babel/eslint-parser", In .eslintrc, add "requireConfigFile": false, to the parserOptions section (underneath "ecmaVersion": 8,) (I needed this or babel was looking for config files I don't have) Run the command to lint a file 6解决 暂时 忽略 掉 这些 先跑通 7 npm run build8解决 不使用 这个 需要 用 process.env.xxxx9 这个是 因为 webpack 5 需要更改 参考这个 https://viglucci.io/how-to-polyfill-buffer-with-webpack-5 关键 plugins: [ loadHtmlWebpackExternalsPlugin(), new webpack.ProvidePlugin({ Buffer: ['buffer', 'Buffer'], }), ] 10可参考 这个 https://www.jiangruitao.com/webpack/copy-webpack-plugin/11 跑起来测试 一遍功能 尤其是 接口 api 调用部分 env.js / httpEnv.js 本节完 ~ 以上文章来自[掘金]-[马克付]本程序使用github开源项目RSSHub提取聚合!
2022年10月18日
0 阅读
0 评论
0 点赞
2022-10-18
从零构建前端日志平台,监控平台-掘金
nodejs服务前端通过调用nodejs api,将所要上报的数据写入本地文件 文件格式以/年/月/日/时/分.log的实行存储 const express = require('express') const fs = require('fs') const path = require('path') const os = require('os') const app = express() // 获取时间 const getDate = () => { const date = new Date(); const year = date.getFullYear().toString() const month = (date.getMonth() + 1).toString(); const day = date.getDate().toString(); const hour = date.getHours().toString(); const minutes = date.getMinutes().toString(); return { date, year, month, day, hour, minutes } } // 获得文件的绝对路径和文件名称 const getAbsolutePath = () => { const { year, month, day, hour, minutes } = getDate() const absolutePath = path.join(year, month, day, hour) return [absolutePath, minutes] } // 检查目录是否存在,不存在则创建 const checkAndMdkirPath = (dirpath, mode = 0777) => { if (!fs.existsSync(dirpath)) { let pathtmp; dirpath.split(path.sep).forEach(function (dirname) { console.log('dirname', dirname) if (pathtmp) { pathtmp = path.join(pathtmp, dirname); } else { pathtmp = dirname; } if (!fs.existsSync(pathtmp)) { if (!fs.mkdirSync(pathtmp, mode)) { return false; } } }); } return true; } // 的到测试数据 const getLogs = () => { const date = new Date(); const message = 'test message' return JSON.stringify({ date, message }) } // 写入log const fileLogs = () => { const [absolutePath, filepath] = getAbsolutePath() const mkdirsuccess = checkAndMdkirPath(absolutePath) if (!mkdirsuccess) return const logs = getLogs() fs.appendFile(`${absolutePath}/${filepath}.log`, logs + os.EOL, (err) => { if (err) throw err; console.log('The file has been saved!'); }); return logs } // 浏览器访问localhost:3000, 写入日志到本地 app.get('/', function (req, res) { const logs = fileLogs() res.send(logs) }) // 监听端口 app.listen(3000) 启动nodejs服务,node ./index.js,访问localhost:3000,浏览器返回结果 当前服务下会多出一个以年月日时分的目录,文件名字时当前时间的分钟.log filebeatfilebeat,监听上一步骤nodejs文件变化,获取文件内容,为什么不用logstash呢?因为filebeat比logstash更轻量,占用内存更小,如果在没有清洗数据的前提下(清洗数据logstash有优势),filebeat比logstash更有优势。# filebeat mac下载,其他版本请访问上述链接 curl -L -O https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-8.4.3-darwin-x86_64.tar.gz tar xzvf filebeat-8.4.3-darwin-x86_64.tar.gz graph LR 本地文件 --> filebeat获取日志 解压,进入解压后的文件夹,编辑filebeat.yml为如下内容,读取nodejs项目下的日志文件,输出日志文件到控制台filebeat.inputs: - type: filestream paths: - /nodejs项目的绝对路径/**/*.log output.console: pretty: true 执行命令./filebeat -e -c filebeat.yml 输出如下: 其中,messag字段端内容为我们mock的用户日志,这个时候ctrl + c,结束filebeat进程,在重新执行上面的命令,会发现控制台上没有了输出,因为filebeat已经消费过现有的log数据了,要想重新输出之前的内容,可以删除执行命令:rm -rf data/registry/filebeat,删除filebeat的记录数据,记录数据如下{"op":"set","id":1} {"k":"filestream::.global::native::19630011-16777223","v":{"cursor":null,"meta":{"source":"/Users/xxx/tools/fe-log-server/2022/10/14/17/27.log","identifier_name":"native"},"ttl":0,"updated":[281470681743360,18446744011573954816]}} {"op":"set","id":2} {"k":"filestream::.global::native::19630011-16777223","v":{"updated":[2061957913080,1665972877],"cursor":null,"meta":{"source":"/Users/xxx/tools/fe-log-server/2022/10/14/17/27.log","identifier_name":"native"},"ttl":1800000000000}} {"op":"set","id":3} {"k":"filestream::.global::native::19630011-16777223","v":{"updated":[2061958151080,1665972877],"cursor":{"offset":61},"meta":{"identifier_name":"native","source":"/Users/xxx/tools/fe-log-server/2022/10/14/17/27.log"},"ttl":1800000000000}} 其中offest记录了filebeat当前消费文件的偏移量,也可以手动修改这个字端,然后重新启动filebeat,查看效果kafka让我们想一想,当我们的日志量非常巨大的时候,直接将日志写入es,很可能造成日志的堆积和丢失,为了解决这个问题,让我们引入消息中间件,kafka,如果你按照最上面的方式启动docker-compose,kafka就会被启动的,让我们一起来测试一下kafka 首先先进入kafka容器 通过docker-compose ps查看kafka容器name,加入name是elk-kafka-1 执行下面命令,进入kafka docker container exec -it elk-kafka-1 bash 创建一个生产者 kafka-console-producer.sh --topic quickstart-events --bootstrap-server localhost:9092 创建一个消费者 kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic quickstart-events --from-beginning 随后你就可以在kafka的生产者容器中随意写入一些内容,kafka消费者会呈现出对应的内容 创建一个topic kafka-topics.sh --bootstrap-server localhost:9092 --create --topic my-topic --partitions 1 --replication-factor 1 --config max.message.bytes=64000 --config flush.messages=1 查看topic列表 kafka-topics.sh --list --bootstrap-server localhost:9092 其他具体操作可以参考:# 真的,Kafka 入门一篇文章就够了filebeat输出日志到kafka 删除filebeat的offest缓存 rm -rf data/registry/filebeat 修改filebeat的filebeat.yml文件,内容为 filebeat.inputs: - type: filestream paths: - '/Users/pengcli/tools/fe-log-server/**/*.log' output.kafka: # initial brokers for reading cluster metadata hosts: ["localhost:9093"] # message topic selection + partitioning topic: 'my-topic' required_acks: 1 compression: gzip max_message_bytes: 1000000 重启filebeat ./filebeat -e -c filebeat.yml 进入kafka容器,启动消费者 kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic my-topic --from-beginning 访问localhost:3000,访问nodejs服务,nodejs将log数据首先写入到本地文件,其次filebeat通过监控本地文件的变化(生产环境可以设置filebeat的input为containers),将数据输出到kafka。消费者输出日志如下 数据流程 graph LR 前端数据 --> nodejs服务 --> 写入本地文件 --> filebeat --> kafka logstash读取kafka数据,并输出到es,logstash的用法和filebeat的用法相似,只不过中间多了一层filter,可以对数据进行清洗,过滤。目前此项目还没有用到数据过滤的流程,其实可以用filebeat代替logstash,这里为了多学习一下,所以采用logstash,获取kafka的数据,并最终将数据输出到es中 进入logstash容器,首先查看容器name,然后进入 docker container exec -it elk-logstash-1 bash 消费kafka数据 logstash -f /usr/share/logstash/pipeline/logstash.conf 其中,/usr/share/logstash/pipeline/logstash.conf这个文件是通过docker-compose中的logstash下的volumes做的映射,映射代码 logstash: ... volumes: - ./logstash/pipeline/:/usr/share/logstash/pipeline - xxx 其中,logstash.yml我们已经提前在根目录下创建完成,具体路径是./logstash/pipeline/logstash.yml,其中内容如下input { kafka { id => "my_plugin_id" bootstrap_servers =>["kafka:9092"] topics => ["my-topic"] group_id => "filebeat" auto_offset_reset => "earliest" type => "pengclikafka" ssl_endpoint_identification_algorithm => "" } } output { elasticsearch { hosts => ["es01:9200"] index => "logstash-system-localhost-%{+YYYY.MM.dd}" } } 简单来说,就是读取从头开始读取kafka数据,topics是my-topic,输出到es中,es的索引是logstash-system-localhost-%{+YYYY.MM.dd},其中%{+YYYY.MM.dd}是logstash中的变量注意,如通过docker-compose启动服务,我们的bootstrap_servers是kafka:9092,kafka这个name则是我们在docker-compose文件中定义好的 如果报错Logstash could not be started because there is already another instance using the configured data directory. If you wish to run multiple instances, you must change the "path.data" setting.,则执行下面下面命令,删除.lcok文件 rm -r ./data/.lock kibana数据展示ok,到目前为止,我们已经成功将数据通过nodejs服务,写入到了es集群中了,现在我们需要配置下es的dataViews,访问本地链接http://localhost:5601/app/management/kibana/dataViews 点击右上角的 create data view按钮,进入编辑页面 编辑完成,则可以通过kibana的discover来查看数据了通过nodejs查询es数据目前为止,我们已经可以将数据成功写入到es集群中了,并成功将它们展示出来,如果到了这一步,我们已经成功的搭建了一个前端日志平台,如果我们需要前端监控平台来展示前端的性能监控,异常监控等等,我们需要在构建一个前端dashboard,需要nodejs从es集群中读取数据,那么如何做呢,代码如下const { Client } = require('@elastic/elasticsearch') const client = new Client({ node: 'http://localhost:9200', }) const essearch = async (req, res, next) => { try { const result = await client.search({ index: 'logstash-system-localhost-2022.10.13', body: { "query": { "match_all": {} } } , }) res.json(result) } catch (err) { res.json(err) } } 其中,如果想要验证query部分的正确性,可以访问本地链接,http://localhost:5601/app/dev_tools#/console 关于kibana的其他查询语句,本文不做过多介绍,可以参考这篇文章# Elasticsearch Query DSL查询入门 你可以写一个定时器,每分钟获取es的数据,然后持久化到mysql中,具体细节这里不再详聊最后这就是如何搭建一个前端日志平台,或者前端监控平台的详细步骤。当然,如果是在生产环境中,我认为会简单一些,我们需要吧一些工具,如elk封装进k8s中,我想这都是现成的,我们只需要写一些配置文件就可以了,然后在通过nodejs将日志写进容器日志文件就好了,其他的流程都是一样的参考链接 # Elasticsearch Query DSL查询入门 # 今天聊:60 天急速自研-前端埋点监控跟踪系统 # 一篇讲透自研的前端错误监控 参考书籍陈辰老师的:从零开始搭建前端监控平台以上文章来自[掘金]-[躺赢局局长]本程序使用github开源项目RSSHub提取聚合!
2022年10月18日
0 阅读
0 评论
0 点赞
2022-10-18
技术分享:可伸缩的精简化研发流程管理方案-掘金
研发任务重,手动同步状态和信息,分身乏术;信息不透明,跨职能成员协调难、沟通成本高;负责人到任,项目细节和代码信息却无从了解;……传统研发流程中,机械重复和信息孤岛或成为阻碍高效协作的头号因子。数字化与信息化的浪潮袭来,基于系统和工具优化管理方式,构建数据闭环和流程自动化是研发提效的主旋律。本文将从需求痛点解析和解决方案建议两个方面,对研发效能优化展开解读,帮助企业更好地打造坚固、可持续发展的研发生态。一、研发流程管理中,企业的关键需求和痛点是什么?01 五个关键需求企业研发流程管理的五个关键需求分别是安全、自主可控、高效、低成本和可拓展。 安全性。包括代码安全、数据安全等。企业可以使用独立的代码仓库、依赖服务/数据可私有化等提高安全性。 自主可控性。企业的核心业务应自主可控、不受限于外部;常通过可扩展的、可信的开源组件提供自己的服务实现。 高效性。持续透明的研发流程是高效运转的低线。企业应建立有效的敏捷项目管理机制,并结合DevOps进行持续集成与构建,追求更高效的研发流程管理。 低成本。项目研发要把资源用在刀刃上——通过合理的资源调配,产生尽可能低的附加成本,将有限的资源发挥出最高性价比。 可扩展性。满足当下技术需要的同时,企业还应当与可扩展性共成长,将可持续发展贯彻到底。 02 人治管理痛点人治管理模式下,研发流程管理非常灵活,但也存在诸多限制:项目信息不透明、代码同步滞后、状态更新耗费时力、信息传递易出错等等;更重要的,项目信息和研发持续输出难以形成良性闭环,信息孤岛极大地限制了管理优化的上限。其次,由于个体能力差异和能力阈值限制,疏忽和错误总是在所难免;身经百战的老手如若缺乏趁手兵器,也无法保证高效交付高质量成果。除此之外,随着研发效能越来越受企业重视,研发流程管理也延伸出更多的诉求: 有没有一种更稳定、可控的管理方式? 企业如何根据自身情况定制方案,解决问题? 哪些可借鉴的流程管理经验可加速突破难关? 如何实现低成本、高效益的研发流程优化? 在信息化的旅程中,更多基于人治的管理痛点和需求逐渐浮现,企业也开始探求更好的研发流程管理办法和方案。二、基于SaaS的研发流程管理方案许多实践经验发现,小规模研发团队的效率有时会更高。因为团队越大,部门越多,同步和沟通就变得复杂,再加上缺乏合适的工具佐助,协同成本便会大大增加。相比之下,使用系统/工具搭建流程闭环,或许是更高效的管理方式。而基于系统提效的核心就是解决协同问题——代码协同、项目协同,以及代码和项目间的协同。01 代码协同工具——GitLab对所有研发型企业来说,其核心资产就是代码,而云版GitLab可以满足代码管理、CI/CD、知识管理等需求。小规模团队使用云版GitLab,甚至可以不需要Jenkins或运维团队;如果想要进行代码私有化管理,可以考虑托管版的GitLab。同时,GitLab还拥有丰富的拓展能力,比如Jenkins、镜像仓库、maven仓库、K8S集成等等,对于打通研发全流程有显著意义。02 容器化工具——Kubernetes随着研发团队的规模逐渐变大,具备专业的运维团队,需要更多的资源协调能力时,企业可能会考虑选择容器化工具如Kubernetes。在GitLab使用K8S集成可以完成自动编排,让部署容器化应用简单又高效。代码是研发流程中最重要的产出,而GitLab以代码为核心,能够以极低的代价(甚至无需运维成本)实现简单的CI/CD流程,还能以私有化部署解决代码管理问题,提升代码协同管理的效率。显然,GitLab解决了部分的持续集成问题,但是在定制化项目研发流程和项目信息协同方面,却不一定能满足企业需求,因此我们需要一个可将两者结合的研发流程管理方案。三、精简的研发全流程管理方案:LigaAI+GitLabLigaAI是新一代智能研发协作工具,通过AI赋能研发协作,解放人工机械工作,让人工智能成为企业生产力的一部分。LigaAI解决项目信息协同问题,而GitLab通过DevOps解决代码协同问题;二者的集成结合可进一步实现项目和代码的有效协同,最终达成三个层面的研发效能提升目标。01 LigaAI+GitLab,如何实现「项目-代码」协同?LigaAI与GitLab的集成实现了项目信息和代码信息的双向同步。研发团队可以直接在LigaAI查看GitLab的代码提交和合并请求记录,还能直接创建分支、提交合并请求,快速轻松地实现代码管理。完成集成后,使用LigaAI丰富的工作表组件,研发管理者可在工作台清晰地了解成员效能与代码提交情况,实现研发效能可视化,更及时地作出布局调整与管理。通过配置【LigaAI-智能助理】,执行以创建Git提交为触发节点的自动执行规则,自动化研发协作流程,消除更新、同步和通知等简单机械的任务;或者使用LigaAI IDE插件中的模板,快捷提交代码并自动提取关联工作信息,减少重复操作,释放更多生产力。02 LigaAI+GitLab,如何实现研发流程可拓展性?LigaAI支持多种外部集成方式,如工具集成开发、丰富的Open API和WebHook配置等,串联跨系统/工具的项目和代码信息,赋能企业打造研发全流程的信息闭环。通过形如「LigaAI + GitLab + Jenkins + K8S + IDE插件 + 飞书WebHook」的拓展应用,在完成代码管理和项目管理的同时,还可以借助人工智能等信息化工具,建立开发信息规范、提升代码质量、构建自动化研发流程,并培养强大的可拓展能力、大规模部署能力和容器化管理能力,最大程度地提升研发效率。# Liga总结研发效能优化与提升是企业降本增效的重要命题。与人治管理相比,基于系统的研发流程管理方法更加符合企业定制化管理和低成本转型的需求。「LigaAI+GitLab」的精简化流程管理方案能够在实现项目协同和代码协同的同时,打通项目信息与研发持续输出的壁垒,完成项目与代码间的协同,并通过丰富的可拓展方案打造研发全流程数据闭环,高效赋能研发团队稳步提升。关于 LigaAILigaAI是新一代智能研发协作平台。我们以人工智能技术为核心,致力于通过AI场景化繁为简,提升协作效率,赋能广大研发团队。从开发者的具体工作场景出发,LigaAI通过人工智能将开发者们从繁杂琐事中抽离出来,为其提供简洁、智能的协作体验,也为不同类型的组织提供数字化、个性化、智能化的项目协作平台。想要了解更多程序人生、敏捷开发、项目管理、行业动态等消息,欢迎关注
[email protected]
了解更多详情,或点击我们的官方网站 LigaAI-智能研发协作平台线上申请体验。以上文章来自[掘金]-[LigaAI]本程序使用github开源项目RSSHub提取聚合!
2022年10月18日
1 阅读
0 评论
0 点赞
2022-10-18
cMake进阶之使用vcpkg管理库-掘金
command:命令的名字 args: 参数列表。多个参数使用空格隔开。 2. cmake_minimum_required 含义设置项目要求的CMake最低版本号 示例cmake_minimum_required(VERSION 2.8) 3. add_executable 含义 使用指定的源文件给项目添加一个可执行文件 格式add_executable( [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] source1 [source2 ...]) 参数介绍: name:该命令调用列出的源文件来构建的可执行目标。 对应于逻辑目标名称,在项目中必须是全局唯一的。构建的可执行文件的实际文件名是基于本机平台的约定。 WIN32:如果给出WIN32,则在创建的目标上设置属性WIN32_EXECUTABLE。 MACOSX_BUNDLE:如果给定MACOSX_BUNDLE,将在创建的目标上设置相应的属性。 EXCLUDE_FROM_ALL:如果给定EXCLUDE_FROM_ALL,将在创建的目标上设置相应的属性。 source:源码列表。 示例add_executable (CMakeClient0331 "CMakeClient0331.cpp" "CMakeClient0331.h") 4. project 含义为整个工程设置一个工程名 格式project ( [LANGUAGES] [...]) project ( [VERSION [.[.[.]]]] [LANGUAGES...]) 参数介绍: 二、cmake 命令生成一个项目的构建系统cmake [] cmake [] cmake [] -S -B 使用 作为构建树,使用 作为源树。指定的路径可以是绝对路径,也可以是相对于当前工作目录的路径。源树必须包含一个CMakeLists.txt文件。如果构建树还不存在,将自动创建它。例如:cmake -DCMAKE_BUILD_TYPE=Release -S . -B build Build a Project cmake --build [] [-- ] Install a Project cmake --install [] Open a Project cmake --open Run a Script cmake [{-D =}...] -P Run a Command-Line Tool cmake -E [] Run the Find-Package Tool cmake --find-package [] View Help cmake --help[-] 三、跨平台 C++ 库管理工具: vcpkg 安装1. 使用 gitbash 下载vcpkggit clone https://github.com/microsoft/vcpkg cd vcpkg ./bootstrap-vcpkg.sh #powershell上使用:.ootstrap-vcpkg.bat 2. 使用 powershell 安装您的项目所需要的库:进入vcpkg目录cd vcpkg 安装库.vcpkg install [packages to install] 安装一个库,这里以之前提到过的 eigen3 为例.vcpkg install eigen3 3. 查看当前安装的库支持的平台./vcpkg help triplets 4. 移除一个已经安装的库.vcpkg.exe remove eigen3 5. 使用 search 子命令来查找vcpkg中集成的库:.vcpkg search [search term] 6. 集成到全局Vcpkg提供了一套机制,可以全自动的适配目录,而开发者不需要关心已安装的库的目录在哪里,也不需要设置[ 比如这里我需要在 Visual Studio 中使用 vcpkg,所以也需要运行以下命令 (首次启动需要管理员权限)].vcpkg integrate install CMake需要使用,记住下面的这个路径,在使用cmake构建的时候需要使用 CMAKE——TOOLCHAIN_FILE传入-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake 也就是cmake -DCMAKE_BUILD_TYPE=Release -S . -B build -DCMAKE——TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake 7. 若要移除集成.vcpkg integrate remove linux上可以参考 https://blog.csdn.net/sexyluna/article/details/1152801218. 查看安装列表.vcpkg list 9. 应用cmake -S . -B build -DCMAKE--TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake 10. 其他跨平台C++库管理 conan 安装 python 略过,安装成功后可以查看版本 python --version 安装python的时候会自动安装pip pip install conan 以上文章来自[掘金]-[鲁班代师]本程序使用github开源项目RSSHub提取聚合!
2022年10月18日
1 阅读
0 评论
0 点赞
2022-10-18
手写编程语言-如何为 GScript 编写标准库-掘金
版本更新最近 GScript 更新了 v0.0.11 版本,重点更新了:Docker 运行环境新增了 byte 原始类型新增了一些字符串标准库 Strings/StringBuilder数组切片语法:int[] b = a[1: len(a)];具体更新内容请看下文。前言前段时间发布了 GScript 的在线 playground,这是一个可以在线运行 GScript 脚本的网站,其本质原理是接收用户的输入源码从而在服务器上运行的服务;这简直就是后门大开的 XSS 攻击,为保住服务器我设置了运行 API 的后端服务的用户权限,这样可以避免执行一些恶意的请求。但也避免不了一些用户执行了一些耗时操作,比如一个死循环、或者是我提供 demo 里的打印杨辉三角。这本质上是一个递归函数,当打印的三角层数过高时便会非常耗时,同时也非常消耗 CPU。有几次我去检查服务器时发现了几个 CPU 过高的进程,基本上都是这样的耗时操作,不可避免的会影响到服务器的性能。使用 Docker为了解决这类问题,很自然的就能想到可以使用 Docker,所有的资源都和宿主机是隔离开的,无论怎么瞎折腾也不会影响到宿主机。说干就干,最后修改了 API 执行脚本的地方: string fileName = d.unix("Asia/Shanghai") + "temp.gs" ; s.writeFile(fileName, body, 438); string pwd = s.getwd(); // string res = s.command("gscript", fileName); string res = s.command("docker","run","--rm","-v", pwd+":/usr/src/gscript","-w","/usr/src/gscript", "crossoverjie/gscript","gscript", fileName); s.remove(fileName); r.body = res; r.ast = dumpAST(body); r.symbol=dumpSymbol(body); ctx.JSON(200, r);主要修改的就是将直接执行的 GScript 命令修改为了调用 docker 执行。但其实也还有改进空间,后续新增协程之后可以便可监控运行时间,超时后便会自动 kill 进程。我也将该 Docker 上传到了 DockerHub,现在大家想在本地体验 GScript 的 REPL 时也只需要运行Docker 就能使用。docker pull crossoverjie/gscript docker run --rm -it crossoverjie/gscript:latest gscript当然也可以执行用 Docker 执行 GScript 脚本:docker run --rm -v $PWD:/usr/src/gscript -w /usr/src/gscript crossoverjie/gscript gscript {yourpath}/temp.gs编写 GScript 标准库接下来重点聊聊 GScript 标准库的事情,其实编写标准库是一个费时费力的事情。现在编译器已经提供了一些可用的内置函数,借由这些内置函数写一些常见的工具类是完全没有问题的。对写 GScript 标准库感谢的朋友可以当做一个参考,这里我打了一个样,先看下运行效果:// 字符串工具类 StringBuilder b = StringBuilder(); b.writeString("10"); b.writeString("20"); int l = b.writeString("30"); string s = b.String(); printf("s:%s, len=%d ",s,l); assertEqual(s,"102030"); byte[] b2 = toByteArray("40"); b.WriteBytes(b2); s = b.String(); assertEqual(s,"10203040"); println(s); // Strings 工具类 Strings s = Strings(); string[] elems = {"name=xxx","age=xx"}; string ret = s.join(elems, "&"); println(ret); assertEqual(ret, "name=xxx&age=xx"); bool b = s.hasPrefix("http://www.xx.com", "http"); println(b); assertEqual(b,true); b = s.hasPrefix("http://www.xx.com", "https"); println(b); assertEqual(b,false);其中的实现源码基本上是借鉴了 Go 的标准库,先来看看 StringBuilder 的源码:class StringBuilder{ byte[] buf = [0]{};// append contents to buf, it returns the length of s int writeString(string s){ byte[] temp = toByteArray(s); append(buf, temp); return len(temp); } // append b to buf, it returns the length of b. int WriteBytes(byte[] b){ append(buf, b); return len(b); } // copies the buffer to a new. grow(int n){ if (n > 0) { // when there is not enough space left. if (cap(buf) - len(buf) < n) { byte[] newBuf = [len(buf), 2*cap(buf)+n]{}; copy(newBuf, buf); buf = newBuf; } } } string String(){ return toString(buf); } }主要就是借助了原始的数组类型以及 toByteArray/toString 字节数组和字符串的转换函数实现的。class Strings{ // concatenates the elements of its first argument to create a single string. The separator // string sep is placed between elements in the resulting string. string join(string[] elems, string sep){ if (len(elems) == 0) { return ""; } if (len(elems) == 1) { return elems[0]; } byte[] bs = toByteArray(sep); int n = len(bs) * (len(elems) -1); for (int i=0; i < len(elems); i++) { string s = elems[i]; byte[] bs = toByteArray(s); n = n + len(bs); } StringBuilder sb = StringBuilder(); sb.grow(n); string first = elems[0]; sb.writeString(first); string[] remain = elems[1:len(elems)]; for(int i=0; i < len(remain); i++){ sb.writeString(sep); string r = remain[i]; sb.writeString(r); } return sb.String(); } // tests whether the string s begins with prefix. bool hasPrefix(string s, string prefix){ byte[] bs = toByteArray(s); byte[] bp = toByteArray(prefix); return len(bs) >= len(bp) && toString(bs[0:len(bp)]) == prefix; } }Strings 工具类也是类似的,都是一些内置函数的组合运用;在写标准库的过程中还会有额外收获,可以再次阅读一遍 Go 标准库的实现流程,换了一种语法实现出来,会加深对 Go 标准库的理解。所以欢迎感兴趣的朋友向 GScript 贡献标准库,由于我个人精力有限,实现过程中可能会发现缺少某些内置函数或数据结构,这也没关系,反馈 issue 后我会尽快处理。由于目前 GScript 还不支持包管理,所以新增的函数可以创建 Class 来实现,后续支持包或者是 namespace 之后直接将该 Class 迁移过去即可。本文相关资源链接GScript 源码:https://github.com/crossoverJie/gscriptPlayground 源码:https://github.com/crossoverJie/gscript-homepageGScript Docker地址:https://hub.docker.com/r/crossoverjie/gscript本文来源:手写编程语言-如何为 GScript 编写标准库以上文章来自[掘金]-[Ziu]本程序使用github开源项目RSSHub提取聚合!
2022年10月18日
0 阅读
0 评论
0 点赞
2022-10-17
总结了一下各类软件许可协议-掘金
软件许可证(或软件许可协议)是一种具有法律性质的合同或指导,由软件作者与软件用户签订,用以规定和限制软件用户使用、拷贝、修改和再发布软件(或其源代码)的权利,以及软件作者应尽的义务。常见许可证及其差异根据许可证使用时间,软件许可证可分为终身许可证和年度许可证。 终身许可证,顾名思义,便是一旦与软件开发商达成协议,签订合同后可终身无限制的使用该软件。此类许可证多见于个人用户领域。 年度许可证,指的是客户与软件开发商商签订协议,按年付费来使用该软件。此类软件许可证多见于商业软件领域。相比终身许可证,年度许可证不太像是购买软件,而更像是租赁软件使用,不过却更为灵活。 分发(distribution)指将版权作品从一个人转移到另一个人或公司,如果你是自己使用,不提供给他人,就没有分发。云服务(SaaS)不构成分发,即你使用开源软件提供云服务,不必提供源码。但是,Affero GPL (AGPL) 许可证规定云服务也必须提供源码。常见的许可证主要有 GPL、LGPL、AGPL、MPL、MIT、BSD 和 Apache,各个许可证还包含不同版本。根据使用条件不同,可以将这些许可证大致分为两类:Copyleft 许可证和宽松式许可证(permissive license),主要对使用、修改和分发的场景作出相应约束。宽松式许可证最基本的类型,对用户几乎没有限制。 用户可以使用代码,做任何想做的事情,可以修改代码后闭源。 不担保代码质量,用户自担风险。 用户必须披露原始作者。 宽松式许可证都规定分发软件时,必须保留原始的许可证声明,区别在于要求用户遵守的条件不同。 BSD(Berkeley Software Distribution) —— 特点是可以自由使用、修改、再发布。但是在商用或者个人分发过程中必须带有原来代码的许可证,且不能用原作者相关信息去做宣传。 MIT —— 源自麻省理工学院(Massachusetts Institute of Technology, MIT),是使用最广泛的一种开源许可证。其特点和 BSD 许可证类似,只要在项目的所有副本中包含版权声明和许可声明,就无需承担任何责任。 Apache —— 作为宽松式许可证中的一员,Apache 多了几个限制条件,禁止使用其商标与作者的相关信息进行商业行为,必须明确指出所有修改过的文件。 Copyleft 许可证Copyleft 是一种让程序或其它作品保持自由(是言论自由的自由,而不是“零价格”)的通用方法,并要求对 Copyleft 程序的任何修改和扩展都保持自由。Copyright 直译是"复制权",这是版权制度的核心,意为不经许可,用户无权复制。Copyleft 是理查德·斯托曼发明的一个词,与 Copyright 相对,Copyleft 的含义是不经许可,用户可以随意复制。核心是:修改后的 Copyleft 代码不得闭源,比宽松式许可证的限制要多: 如果分发二进制格式,必须提供源码。 修改后的源码,必须与修改前保持许可证一致。 不得在原始许可证以外,附加其他限制。 对用户的限制从最强到最弱排序:AGPL > GPL > LGPL > MPL。 AGPL(Affero 通用公共许可证) —— AGPL 是 GPL 的一个补充,在 GPL 的基础上加了一些限制。GPL 的约束生效前提是该软件 "发布",有的公司就使用 GPL 组件编写 web 系统,但是不发布系统,只用这个系统在线提供服务,这样就避免了开源系统代码。而 AGPL 要求如果云服务 (即 SaaS) 用到的代码是该许可证,那云服务的代码也必须开源。 GPL(通用公共许可证) —— GPL 和 BSD 区别还是很大的,GPL 主张代码及衍生代码的开源,不允许修改后和衍生的代码做为闭源的商业软件进行发布和出售。如果已发布商业软件源码里含有 GPL 开源软件源码,则必须对该商业软件进行开源或者下架处理。 LGPL(Lesser 通用公共许可证) —— LGPL 允许商业软件通过类库引用的方式使用 LGPL 类库,而不需要开源商业软件源码。 MPL(Mozilla 公共许可证) —— 在商业软件中,如果含有 MPL 许可证的代码在单独的文件内,其他新增的文件就可以避免开源。 如何选择乌克兰程序员 Paul Bagwell,画了一张分析图,说明应该怎么选择。下面是制作的中文版:一些示例包括: Apache:需要 Apache 2.0 协议。 Cloud Native Computing Foundation:默认规定 Apache 2.0 协议。 GNU:建议大多数程序使用 GNU GPLv3 协议。 NPM packages:绝大多数使用 MIT 或非常相似的 ISC 协议(等同于 BSD 2 和 MIT)。 OpenBSD:更建议 ISC 协议。 Rust:程序包基本上都同时使用 MIT 和 Apache 2.0 两个协议来授权。 WordPress:插件和主题必须为 GNU GPLv2 协议(或更高版本)。 软件通常来说,我们推荐使用最 Copyleft 而不影响目的的许可证。对大多数程序,我们推荐使用最新版的 GPL。它强大的 Copyleft 适合所有类型的软件,并对用户的自由有很多保护。为了将来许可证的升级,请声明 “版本 3 或者任何新版本”,这样你的程序就 在许可证层面兼容其他将来按照后续 GPL 版本发布的程序。小程序对大多数小程序,使用 Copyleft 是不值得的。我们用300行作为基准:当一个软件包的源码比这个短,Copyleft 带来的好处通常太小,不足以对抗确保许可证的复本总是伴随软件的不便。对这些程序,我们推荐 Apache 2.0 许可证。这是一个弱的、松散的、“顺从型”(非 Copyleft)软件许可证,它有用于避免贡献者和分发者起诉专利侵权的条目。这并不会让软件避免来自专利的威胁(一个软件许可证是做不到的),但它避免了专利持有者打着自由的幌子发布软件,这种情况下专利持有者会相当于做了一次“诱导转向”,然后要求接受者同意专利证书中的非自由条目。在不严格的(顺从型)许可证中,Apache 2.0 是最好的;所以如果你要用一个不严格的许可证,不论什么原因,我们推荐用这一个。库对于库,我们分三种情形。 如果你是专有应用开发者使用自由标准的库,那么你就应该对这些库使用宽松的许可证,比如 Apache 2.0 许可证,这样专有应用就容易包含这些库。 如果开发者已经使用现有的以非自由或不严格的 pushover 许可证发布的库,那么我们建议使用 Copyleft 许可证 LGPL。较为宽松的 GPL(LGPL)允许私有软件开发者使用其保护起来的库,LGPL 提供了给用户自由的弱 Copyleft。 对于提供了特别设计,并且不会与现有非 Copyleft 或非自由库竞争的,我们推荐使用原始的 GNU GPL。 服务器软件如果其他人很有可能会给你在服务器上跑的软件制作改进版并且不向其他人分发他们的版本,而且你担心这将把你的版本置于一个不利的地位,我们推荐 AGPL。AGPL 的条目和 GPL 几乎相同,唯一实质的区别是它有一个额外的条件确保通过网络用这个软件的人们可以获得它的源代码。专利某些许可证(Apache 2 和 GPL v3 等)包含明确的条款,授予用户许可使用软件所包含的所有专利。BSD 3条款净化版许可证、开放数据库许可证和知识共享许可证明确声明它不授予贡献者专利的任何权利。另一些许可证(BSD、MIT 和 GPL v2)没提到专利。但是一般认为,它们默认给予用户专利许可,不构成侵犯专利。除非有明确的"保留专利"的条款,使用开源软件都不会构成侵犯专利。案例 2019 年,在数字天堂北京网络技术有限公司 诉 柚子北京科技有限公司的案件中,柚子北京 由于开发人员在 2015 年使用了 数字天堂 的 HBuilder 软件工具中三款插件的部分源代码,未遵守开源软件许可证,将具有开源要求的软件产品作为商业产品。被开源软件的著作权人诉请违约和侵权,故而承担法律责任。 2021 年 4 月 30 日,罗盒公司状告风灵公司侵权获赔 50 万元,同时要求风灵公司停止侵权行为。在该案件中原告罗盒公司,独立开发 “罗盒 (Virtual App) 插件化框架虚拟引擎系统 V1.0”(简称 VirtualApp V1.0),在 2016 年引入 GPL3.0 许可证,于 2017 年取得计算机软件著作权登记证书,且声明用于商业用途请购买商业授权。2018 年原告发现名为 “点心桌面” 的软件使用了 VirtualApp V1.0 的代码,经过源码分析对比,发现两者之间高度相似,遂起诉被告福建风灵公司。经法院审判被告赔偿原告为制止侵权行为而支出的合理费用 50 万元。此次判决是中国首个明确 GPL3.0 许可证具有法律效力的案例。 2021 年 12 月中旬,抖音海外版 TikTok 上线一款名为 TikTok Live Studio 的 APP,有网友发现,此软件违反 GPL 许可证,违规使用开源软件 OBS(一个免费的开源视频录制和视频实时流软件,且允许任何人免费应用和商用)的源代码,既然允许商用,但是为什么还会被曝违规呢?这里就需要再科普一下 GPL 许可证,GPL 许可证具有很强的传染性,如果一款软件使用 GPL 许可证的开源软件源码,那么该软件也必须采用 GPL 许可证,进行开源或者下架处理。此事曝光之后,OBS 开发者证实此事,TikTok 也对此事进行了回应,并删除 TikTok Live Studio 的下载页面。 建议 软件开发者使用开源软件时,需要谨慎选择开源软件,关注其开源许可证的内容及相关条件,避免潜在的法律风险。 企业应当建立一个完善机制,识别企业中所使用的开源软件清单,明确对应的开源许可证及权利约束,及时规避相关合规风险。 通过隔离机制避免开源许可证传染,如对于 MPL 许可证下代码的使用,应把该许可证的代码放在单独的文件内避免许可证传染;LGPL 下的代码,可采用动态链接调用该许可证的库实现隔离。 有些组件是存在多种许可证的,可能不同目录文件指定的许可证类型不一样,要特别注意。 有些组件你没有直接依赖,但是可能存在间接依赖的情况,你需要特别注意查看相关组件的依赖关系。 使用 murphysec 开源工具扫描您的代码目录,它会帮您一键识别出来您的代码项目中使用的所有开源组件,包括直接依赖和间接依赖的组件清单,同时列出所有组件对应的开源许可证信息;根据报告的提示可以明确看到对应组件的许可证在什么场景下存在许可证合规风险;根据许可证的合规风险提示,来判断您的项目是否存在违反的可能性,并调整您所引入的组件,来解决这个风险。 使用在源代码的根目录中创建一个文本文件(通常命名为 LICENSE 或 LICENSE.txt),并将许可证文本复制到该文件中。将 [year] 替换为当前年份,并将 [fullname] 换为版权所有者的姓名。如果可以,添加软件许可协议到项目程序包的描述中(例如:Node.js、Ruby、和 Rust),这将确保许可证显示在软件包目录中。参考资料 附录 如何选择开源许可证? 为什么GPL是更好的开源许可证? 总结了一下程序员们都应该知道的各类开源许可证及合规相关的知识 以上文章来自[掘金]-[zkj]本程序使用github开源项目RSSHub提取聚合!
2022年10月17日
0 阅读
0 评论
0 点赞
2022-10-17
聊聊高大上的变异测试-掘金
我正在参加「掘金·启航计划」一、变异测试简介变异测试**是一种基于故障注入的测试技术****,**将错误代码插入到被测代码中,以验证当前测试用例是否可以发现注入的错误。我认为该测试手段理论上属于白盒测试范畴。变异测试的主要目的是为了验证测试用例的有效性,在注入变异后,测试用例能发现该错误,则表明用例有效的;反之,表明测试用例是无效的,需要补充该变异的测试用例。变异测试有助于评估测试用例的质量,以帮助测试人员编写更有效的测试用例。测试人员设计的测试用例发现的变异体越多,表明其设计的测试用例质量就越高。在深入理解变异测试之前,让我们先搞懂和它相关的几个核心概念。1) 变异可以理解为对源代码的任何更改,也可以理解为引入的故障。2) 变异体可以理解为被测代码的变异版本,即已经在被测代码中注入变异的代码。当测试用例在变异体版本的代码运行时,理论上该测试用例执行的结果应该与原被测代码执行的结果不同。 存活的(survived)变异体: 变异注入的错误并不能被测试用例感知,这种情况称为变异体能够“存活”,说明测试用例的有效性存在问题,需要对测试用例进行补充和修正。 杀死的(killed)变异体: 在变异体代码上执行测试不通过,说明变异注入的错误能够被测试用例T感知到,测试用例能够“杀死”此变异,说明此测试用例是有效的。 等价的变异体:这个其实也很好理解,通过下面例子介绍下。源代码: for(int i=0;i
2022年10月17日
0 阅读
0 评论
0 点赞
1
2
...
129