收集器, 一种通用的、 从流生成复杂值的结构。 只要将它传给 collect 方法, 所有的流就都可以使用它了。
收集器可以做很多事情,例如:计数、分组、归并、求和等。
收集器汇总 序号方法含义1Collectors.averageingInt
Collectors.averagingLong
Collectors.averagingDouble平均值2Collectors.collectingAndThen统计并转换3Collectors.counting计数4Collectors.groupingBy分组5Collectors.mapping替换6Collectors.maxBy
Collectors.minBy最大值、最小值7Collectors.partitioningBy按Boolean分组8Collectors.reducing归并9Collectors.summarizingInt
Collectors.summarizingLong
Collectors.summarizingDouble获得统计结果对象10Collectors.summingInt
Collectors.summingLong
Collectors.summingDouble求和11Collectors.toList将流转换成list12Collectors.toSet将流转换成set13Collectors.toCollection将流转换成Collection14Collectors.toMap
Collectors.toConcurrentMap将流转换成map Collectors.averagingInt、Collectors.averagingLong、Collectors.averagingDouble:
统计Stream<T>流中, (根据)每个元素T得到的类型为int/long/double的数值的平均值。
/** * 统计Stream<T>流中, (根据)每个元素T得到的类型为int/long/double的数值的平均值。 * * 注:统计结果为Double。 * * 注:Stream的collect方法,签名为: * <R, A> R collect(Collector<? super T, A, R> collector) * * 注:Collectors的caveragingLong方法,签名为: * Collector<T, ?, Double> averagingInt(ToIntFunction<? super T> mapper) * * 注:Collectors的caveragingLong方法,签名为: * Collector<T, ?, Double> averagingLong(ToLongFunction<? super T> mapper) * * 注:Collectors的caveragingLong方法,签名为: * Collector<T, ?, Double> averagingDouble(ToDoubleFunction<?
在Vue3 + TS项目中,我们经常需要对一些按钮进行防抖处理,以避免用户频繁点击而导致的性能问题。因此,我们可以封装一个全局的按钮防抖函数来简化代码,提高开发效率。
实现步骤 创建 src/utils/debounce.ts 文件。
在 debounce.ts 文件中,引入 lodash 库,并编写防抖函数。
import _ from 'lodash'; export function debounce<T extends (...args: any[]) => any>( fn: T, delay: number = 300 ): T { return _.debounce(fn, delay, { leading: true, trailing: false }) as T; } 在 src/main.ts 文件中,将防抖函数挂载到 Vue 实例的原型上,以便在全局使用。
import { createApp } from 'vue'; import App from './App.vue'; import { debounce } from './utils/debounce'; const app = createApp(App); app.
对于经常使用linux系统的朋友们来说,基本常用的shell命令是少不了的,下面这篇文中就为大家总结了Linux shell的常用命令,有需要的朋友们可以参考借鉴,下面来一起学习学习吧。
导读
使用Linux shell是一些程序员每天的基本工作,但我们经常会忘记一些有用的shell命令和技巧。当然,命令我能记住,但我不敢说能记得如何用它执行某个特定任务。需要注意一点的是,有些用法需要在你的Linux系统里安装额外的软件。下面话不多说了,来看看详细的内容吧。
检查远程端口是否对bash开放:
echo >/dev/tcp/8.8.8.8/53 && echo "open"
让进程转入后台:
Ctrl + z
将进程转到前台:
fg
产生随机的十六进制数,其中n是字符数:
openssl rand -hex n
在当前shell里执行一个文件里的命令:
source /home/user/file.name
截取前5个字符:
${variable:0:5}
SSH debug 模式:
ssh -vvv user@ip_address
SSH with pem key:
ssh user@ip_address -i key.pem
用wget抓取完整的网站目录结构,存放到本地目录中:
wget -r --no-parent --reject "index.html*" http://hostname/ -P /home/user/dirs
一次创建多个目录:
mkdir -p /home/user/{test,test1,test2}
列出包括子进程的进程树:
ps axwef
创建 war 文件:
jar -cvf name.war file
测试硬盘写入速度:
dd if=/dev/zero of=/tmp/output.img bs=8k count=256k; rm -rf /tmp/output.
⛳目录 认识虚拟环境Python中的虚拟环境工具 🎈为什么需要虚拟环境? 辛辛苦苦写好一个项目,各种版本的第三方组件,凌乱的配置文件,在自己电脑上运行的十分流畅,想分享给同事使用,迁移过去之后,重建配置,各种跑不起来。一些比较特殊的工具需要依托于不同的Python版本,就像 robotframework,仅仅支持Python 2.7和>= 3.6。第三方库的管理,打包的时候避免有其他干扰的包。等等… 🎈认识虚拟环境 本节课我们先要知道什么是虚拟环境。接下来再介绍一些Python中的虚拟环境工具。在我们平时的工作中,可能存在一台电脑中拥有多个Python版本的情况。比如我们有一个Python2.7的版本。还有一个Python3.8的环境。他们两个都存在于我们当前的系统中。这就造成了一个问题。两个版本可能因为在同一个环境下造成使用的pip与Python的第三方包冲突的问题。 为了解决这个问题。我们在当前的。系统中专门创建了一个Python2.7的环境。这个环境中只有Python2.7的pip以及Python2.7的解释器。而Python3.8也可以创建属于一个自己的虚拟环境。这两个虚拟环境独立存在。并且可以做到互不冲突,互不影响。这就是虚拟环境的作用与目的。==我们只需要在各自的虚拟环境中,按照自己的需要的Python软件以及版本进行安装。这些软件与指定的版本也只针对于当前的虚拟环境。不会影响到其他的虚拟环境。==通过这里大家可以联想一下。我们使用pycharm的时候创建的每一个Python项目,他们都是各自的一个独立的虚拟环境,互相不会受到影响。 🎈Python中的虚拟环境工具 接下来让我们了解一下Python中都有哪些创建虚拟环境的软件。
Virtualenv
pyenv
第一个是virtualenv。它是非常常用的虚拟环境工具。不过它依赖于当前系统中都有哪些Python版本。比如我的电脑中有Python2.7和Python3.6。以及Python3.8的版本。那么virtualenv就只能在这三个版本中去创建虚拟环境。但是vitualenv使用简便。也是受到很多Python爱好者的追捧。第二个是pyenv。它和virtualenv一样,都是创建虚拟环境的工具。不过,pyenv并不依赖当前系统中都拥有哪些Python版本。也就是说,只要是Python拥有的版本,pyenv都可以在当前电脑中创建虚拟环境。它的做法就是先把我们希望创建的虚拟环境的Python版本安装到本地,然后再进行虚拟化操作,不过它的缺点是操作较为复杂,并且也是依赖于virtualenv。甚至我们可以认为,pyenv最终还是需要通过virtualenv来进行虚拟环境的创建,由于pyenv操作相对复杂,所以我们本节课主要介绍virtualenv的使用方法。在日后对Python使用更加娴熟之后,再去关注pyenv可能会更加轻松,Virtualenv也是Python的第三方包。不过它和IPython一样,都是在命令行下去执行的
我们通过pip install virtualenv来下载并安装它。当安装完成之后,我们希望把虚拟环境创建在哪个目录下,就要提前进入到这个文件夹,这个也是选择创建虚拟环境的目录.
接下来,输入virtualenv -p python3 pyenv回车程序将会在我们选择的目录下创建一个虚拟环境的文件夹。其实虚拟环境就是一个文件夹。接下来,我们通过调用./penv/bin/activate来启动虚拟环境。Windows系统,可以直接进入到pv文件夹下的Scripts文件夹中,直接输入.\activate回车,就可以进入到虚拟环境
如果我们想退出虚拟环境。我们只需要直接输入deactivate,就可以将退出我们现在的虚拟环境。最后,请注意。我们进入的虚拟环境只是在当前我们打开的它们的终端有效。如果我们开启了多个terminal终端,而且需要每一个都在虚拟环境中,则需要对每个terminal终端都执行以上操作才可以。
虚拟环境的好处 虚拟环境(Virtual Environment)是 Python 中用于隔离项目依赖和开发环境的一种机制。它的作用如下:
项目隔离: 虚拟环境允许您在同一台计算机上创建多个独立的 Python 环境,每个环境都可以具有自己的包和依赖关系。这样可以避免不同项目之间的依赖冲突问题,确保每个项目都有独立、干净的开发环境。
依赖管理: 在虚拟环境中,您可以安装和管理项目所需的特定版本的 Python 包和依赖项。这使得您可以精确地控制每个项目所使用的包版本,避免由于包升级或变更而导致的兼容性问题。
可移植性: 虚拟环境使您的项目更具可移植性。您可以将项目的虚拟环境打包并与项目一起分发,以确保其他人在不同的计算机上能够轻松地重现和运行项目。
环境隔离: 虚拟环境提供了一种隔离的开发环境,您可以在其中安装和测试新的 Python 包和工具,而不会对系统的全局 Python 环境产生影响。这使得您可以更安全地尝试新的软件库或工具,而不会破坏您的系统环境。
总而言之,虚拟环境使得多个项目可以独立地开发和运行,避免了依赖冲突和环境污染问题,提供了更好的可移植性和灵活性。这是 Python 开发中非常有用的工具之一,推荐在项目中使用虚拟环境来管理依赖和环境。
虚拟环境和使用不同的解释器都是为了实现项目的隔离和依赖管理,确保每个项目都可以使用所需的特定版本的软件包,但虚拟环境提供了更方便和统一的方式来管理和切换不同的环境。
virtualenv 是一个用于创建独立 Python 环境的工具,它可以用来创建一个隔离的 Python 运行环境,以便在同一台机器上同时管理多个项目所需的不同依赖关系。
virtualenv 并不是一个包或模块,而是一个用于创建和管理独立环境的命令行工具。通过使用 virtualenv,您可以在单个计算机上创建多个相互独立的 Python 环境,并为每个环境选择不同的包和模块版本,而不会相互干扰。
创建一个虚拟环境时,virtualenv 会在指定的目录中创建一个新的 Python 安装,其中包括 Python 解释器和一些必要的库和工具。您可以在虚拟环境中安装和管理项目所需的特定版本的软件包,而不会影响系统级的 Python 安装和其他项目的依赖关系。
简而言之,virtualenv 是一个用于创建独立 Python 环境的工具,可以帮助您隔离和管理不同项目的依赖关系。
什么是Apache Apache是指Apache HTTP Server,它是由Apache软件基金会开发和维护的一款开源的HTTP服务器软件。它是目前世界上最流行的Web服务器软件之一,被广泛用于搭建和托管网站。Apache HTTP Server的主要功能是接收客户端的HTTP请求,并向客户端提供相应的Web页面或其他资源。它支持多种操作系统,包括Windows、Linux、Unix等,可以在各种硬件平台上运行。Apache的设计目标之一是稳定性和安全性。它通过模块化的架构提供了丰富的功能扩展和灵活性,可以根据具体需求加载不同的模块。这使得开发人员和系统管理员可以根据自己的需求和配置来定制Apache服务器。
Apache还支持多种协议和技术,如HTTP/1.1、HTTPS、CGI、FastCGI、PHP、Python、Perl等,使得开发者可以使用各种编程语言和技术来构建动态的Web应用程序。除了功能强大和可靠性高之外,Apache还受益于其开源的特性。它的源代码对公众开放,任何人都可以查看、修改和贡献代码。这促进了全球开发者社区的参与,使得Apache能够不断改进和适应新的技术和需求。
Apache的多种用途 Apache的用途非常广泛,以下是一些常见的用途:
提供Web服务:Apache HTTP Server是最常见的用途之一,它可以作为Web服务器来托管网站和提供Web服务。它能够处理HTTP请求并将相应的Web页面发送给客户端,支持静态页面和动态内容。构建应用程序服务器:除了简单的静态网页,Apache还支持多种动态内容和应用程序,如PHP、Python、Perl等。它可以作为应用程序服务器,处理和执行动态脚本,并生成动态的Web页面和服务。代理服务器:Apache可以用作代理服务器,充当客户端和其他服务器之间的中介。代理服务器可以缓存请求,提高性能和响应速度,还可以实现负载均衡和反向代理等功能。FTP服务器:Apache还提供了支持文件传输协议(FTP)的模块,可以用作FTP服务器,用于文件共享和传输。虚拟主机托管:Apache支持虚拟主机,可以在一台物理服务器上托管多个域名或网站。这允许多个网站共享同一台服务器,并提供独立的Web服务。安全性和认证:Apache提供了多种安全性和认证的功能,如SSL/TLS加密、基本认证、访问控制等。这使得它成为安全和受保护的Web服务器选择。日志记录和统计:Apache可以记录访问日志和错误日志,帮助管理员分析和监控服务器的运行情况。还可以通过访问日志生成统计数据,了解网站的访问量、用户行为等信息。 下载Apache 可以通过官网进行下载:
Apache官网:Welcome to The Apache Software Foundation!
Apache官网下载页面:Apache Projects Releases
也可以通过Apache Lounge 社区下载:
Apache Lounge 社区:Apache Lounge
Apache Lounge 社区下载页面:Apache VS17 binaries and modules download
有细心的小伙伴会发现这两个页面的域名不一样,这是因为https://www.apache.org/ 是 Apache的官方网站,而 https://www.apachelounge.com/download/ 则是 Apache Lounge 社区提供的 Apache HTTP 服务器的 Windows 版本二进制文件下载网站。
Apache安装 我这里下载的是httpd-2.4.56这个版本,将下载好的压缩包解压出来,然后放到一个合适的位置,我这里是将解压出来的文件夹放到D盘的根目录。(目录中不要出现中文)
然后打开Apache24这个目录中的bin文件夹,然后运行cmd。
然后输入httpd。
这里出现httpd: Syntax error on line 39 of D:/Apache24/conf/httpd.conf: ServerRoot must be a valid directory是因为http.conf中的Define SRVROOT "
使用Android Studio常规方式打包时出现generated successfully for module '' with 0 build variants问题,但是又没有报错,一头雾水,这时我们可以通过别的方式来打release包
1、打开如图所示配置页面,在modules中添加release配置
2、根据以下步骤添加signing config为 上一步骤添加的release
3、打开build Variants,将打包方式变为release
4、使用如下方式就可以打出release包了
WPF对象的属性通常为String类型,但并不总是。类型不符时对其进行String赋值显然是不行的,但是可以通过类型转换类将String转换为对应类型后再进行赋值。
1.类型转换类继承TypeConverter类
2.重写ConvertFrom函数
3.为被赋值类(通过TypeConverterAttribute特征类)标注特征
<local:Human x:Key="human" Name="Tom" Child="LittleTom"/> //特性(可以理解为Java中的注解,但Java的注解参考了特性) [TypeConverterAttribute(typeof(NameToHumanTypeConverter))]//TypeConverterAttribute可简写为TypeConverter(特征类在使用时可省略Attribute) public class Human { public string Name { get; set; } public Human Child { get; set; } } //类型转换器:前端赋值时可能出现类型不符的情况,此时将调用该方法改变数据类型,再赋值 public class NameToHumanTypeConverter : TypeConverter { public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) { string name = value.ToString(); Human human = new Human(); human.Name = name; return human; } } 上述代码中,"LittleTom"将作为参数value被传入ConvertFrom函数,ConvertFrom函数的返回值将被赋值给Child属性
文章目录 弹窗封装: <template> <el-dialog :visible="modalVisible" title="批量导入" centered @close="$emit('close')"> <span>弹窗内容</span> <span slot="footer" class="dialog-footer"> <el-button @click="closeModal">取 消</el-button> <el-button type="primary" @click="onConfirm">确 定</el-button> </span> </el-dialog> </template> <script> export default { props: { // modal是否可见 modalVisible: { type: Boolean, default: false, }, }, data() { return {}; }, methods: { onConfirm() { this.$emit('bulkImport', 11); }, closeModal() { this.$emit('close'); }, }, watch: {}, computed: {}, components: {}, mounted() {}, }; </script> <style lang="less" scoped> </style> 使用弹窗: <template> <el-button type="
数据迁移在各种业务场景中发挥着至关重要的作用。当您的公司将其服务从本地迁移到云端时,数据迁移就会介入,将数据从旧位置传输到新位置。另一种常见的做法可能是更换或升级服务器或存储设备。在这种情况下,数据迁移可确保数据的顺利高效传输,最大限度地减少停机时间和中断。此外,数据迁移可以确保重要信息在新环境中保持准确和可访问,从而帮助维护数据库的完整性和一致性。
在本文中,我们将探讨如何使用dbForge Studio for MySQL和Devart ODBC driver for Oracle将数据从 Oracle 迁移到 MySQL 表。 为什么从 Oracle 数据库迁移到 MySQL 数据库? 您可能出于任何原因需要将数据从 Oracle 迁移到 MySQL 数据库,例如:
与 Oracle 相比,MySQL 更具成本效益。由于 MySQL 是一个开源数据库,因此不需要相关的许可成本。MySQL 因其简单的设置过程和用户友好的界面而简单而灵活。与 Oracle 更复杂且功能丰富的 PL/SQL 语言相比,MySQL 中的语法和命令通常更容易学习和理解。由于其高性能和可扩展性,MySQL 可以高效处理大量数据,同时保持最佳的数据库性能。MySQL 受益于开源社区,该社区提供了大量故障排除和开发支持、资源和文档。社区经常发布 MySQL 数据库的更新和改进,确保其保持可靠和最新。MySQL兼容多种平台和操作系统,可以轻松地与各种编程语言、框架和工具集成,从而使数据迁移更加容易。 先决条件 数据库迁移包括迁移模式、表和数据。为此,我们将下载并使用以下工具:
dbForge Edge
是一个包含四个数据库 IDE 的通用套件,每个 IDE 都允许在不同的数据库系统上执行数据库开发、管理和管理任务,包括 Microsoft SQL Server、MySQL、MariaDB、Oracle、PostgreSQL 和 Amazon Redshift。所有 Studio 中都提供的数据导入功能允许用户快速、轻松地从多个源(包括 ODBC 驱动程序)导入数据。Devart ODBC Driver for Oracle
它是一个可靠且简单的工具,可在 32 位和 64 位 Windows、macOS 和 Linux 上通过 ODBC 兼容工具访问 Oracle 数据库。 使用 ODBC 的优点 在深入研究数据迁移之前,我们先来看看开发人员和组织通过使用 Devart ODBC驱动程序可以获得的好处:
1、什么是JWT JWT(JSON Web Token)是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。
它将用户信息加密到token里,服务器不保存任何用户信息。服务器通过使用保存的密钥验证token的正确性,只要正确即通过验证;应用场景如用户登录。
JWT详细讲解请见 github:https://github.com/jwtk/jjwt
1.1传统Cookie+Session与JWT对比 ① 在传统的用户登录认证中,因为http是无状态的,所以都是采用session方式。用户登录成功,服务端会保证一个session,当然会给客户端一个sessionId,客户端会把sessionId保存在cookie中,每次请求都会携带这个sessionId。
cookie+session这种模式通常是保存在内存中,而且服务从单服务到多服务会面临的session共享问题,随着用户量的增多,开销就会越大。而JWT不是这样的,只需要服务端生成token,客户端保存这个token,每次请求携带这个token,服务端认证解析就可。
② JWT方式校验方式更加简单便捷化,无需通过redis缓存,而是直接根据token取出保存的用户信息,以及对token可用性校验,单点登录,验证token更为简单。
1.2 JWT的组成 三部分:
第一部分为头部(header)第二部分我们称其为载荷(payload)第三部分是签证(signature) 由前两部分组成
各部分之间,用.分隔。 例如:
KV1QiLCJhbGciOiJIUzUxMiJ9.eyJzdWIiiwiaWF0IjoxNTY1NTk3MDUzLCJleHAiOjE1NjU2MDA2NTN9.afw5WFm-TwZltGWb1Xs6oBEk5QdaLzlHxDM73IOyeKPF_iN1bLvDAlB7UnSu-Z-Zs
2、引入依赖 <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.4.0</version> </dependency> 3、编写工具类 编写工具类,静态方法,便于调用:
import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.interfaces.DecodedJWT; import java.util.Calendar; public class JwtUitls { //token超时变量,N(秒)后 public static final int TOKEN_TIMEOUT = 60*60*1; // 密钥 public static final String APP_SECRET = "xxx@#$%^&dong"; //生成token方法:传入用户名、用户ID 作为payload写入,便于后期解析 public static String createToken(int id,String name) { Calendar instance=Calendar.getInstance(); instance.
点击查看 Huggingface详细入门介绍之dataset库
loadset 导入本地文件 import os from datasets import load_dataset data_home = r"D:\数据集路径" # data_dict = { "train": os.path.join(data_home, "train.json"), "test": os.path.join(data_home, "test.json"), } datasets = load_dataset("json", data_files=data_dict) print(datasets) print(datasets["train"][0]) load_dataset("json", data_files=data_dict) json : 表示导入的本地文件是 json文件
C++函数的返回值类型可以是除数组和函数以外的任何类型,非void类型的函数必须向调用者返回一个值,数组只能返回地址。当返回值是指针或引用对象时,需要特别注意:函数返回所指的对象必须继续存在,因此不能将函数内部的局部对象作为函数的返回值。
返回引用的函数 函数可以返回一个引用,这样的目的是为了将该函数用在赋值运算符的左边,因为其他情况下,一个函数是不能直接用在赋值运算符左边的。
返回引用的函数原型的声明方式为:
数据类型 &函数名(参数列表);
#include <iostream> using namespace std; int a[] = {2, 4, 6, 8, 10, 12}; int &index(int i); int main() { index(3) = 16; cout << index(3) << endl; for (int i = 0; i < 6; i++) { cout<<"第"<<i+1<<"个元素:"<<a[i]<<endl; } return 0; } int &index(int i) { return a[i]; } 16
第1个元素:2
第2个元素:4
第3个元素:6
第4个元素:16
第5个元素:10
第6个元素:12
返回指针的函数 指针函数:返回值是存储某种类型数据的内存地址的函数。
返回指针的函数原型的声明方式为:
数据类型 *函数名(参数列表);
#include <iostream> using namespace std; float *input(int &); int main() { int num; float *data = input(num); if (data) { for (int i = 0; i < num; i++) { cout << data[i] << "
这里写目录标题 一、Simulink 系统的仿真与分析1. 设置仿真参数1.1 Solver 参数设置1.2 Data lmport/Export 参数设置 2. 运行仿真与仿真结果分析2.1 运行仿真2.2 仿真结果分析 一、Simulink 系统的仿真与分析 系统的模型建立之后,选择仿真参数和数值算法,便可以启动仿真程序对该系统进行仿真。 1. 设置仿真参数 在系统仿真过程中,事先必须对仿真算法、输出模式等各种仿真参数进行设置。在模型编辑窗口打开仿真参数设置对话框有以下方法。(1) 单击工具栏中的 Model Configuration Parameters 按钮。(2) 选择 Simulation ⟶ \longrightarrow ⟶Model Configuration Parameters 命令。打开的仿真参数设置窗口如下图所示。 在仿真参数设置窗口中,仿真参数分为以下 7 类。(1) Solver 参数:用于设置仿真起始和终止时间,选择微分方程求解算法并为其规定参数,以及选择某些输出选项。(2) Data Import/Export 参数:用于管理工作空间数据的导入和导出。(3) Optimization 参数:用于设置仿真优化模式。(4) Diagnostics 参数:用于设置在仿真过程中出现各类错误时发出警告的等级。(5) Hardware Implementation 参数:用于设置实现仿真的硬件。(6) Model Referencing 参数:用于设置参考模型。(7) Simulation Target 参数:用于设置仿真模型目标。 1.1 Solver 参数设置 Solver(求解算法)是利用模型中所含的信息来计算系统动态行为的数值积分算法。Simulink 提供的求解算法可支持多种系统的仿真,其中包括任何规模的连续时间(模拟)、离散时间(数字)、混杂(混合信号)和多采样率系统。这些求解算法可以对刚性系统以及具有不连续过程的系统进行仿真。可以指定仿真过程的参数,包括求解算法的类型和属性、仿真的起始时间和结束时间以及是否加载或保存仿真数据。此外,还可以设置优化和诊断信息。在仿真参数设置窗口左侧窗格中选择 Solver 选项,在右侧窗格中会列出所有 Solver 参数,如图12-8所示。 (1) 设置仿真起始和终止时间(Simulink time)。在 Start time 和 Stop time 两个编辑框中,通过直接输入数值来设置仿真起始时间和终止时间,时间单位是秒 (s)。(2) 仿真算法的选择(Solver options)。在 Type 下拉列表框中设定算法类别:Fixed-step(固定步长)和 Variable-step(变步长)算法,在 Solver 下拉列表框中选择具体算法。仿真算法根据步长的变化分为固定步长类算法和变步长类算法。固定步长是指在仿真过程中计算步长不变,而变步长是指在仿真过程中要根据计算的要求改变步长。对于这两类算法,它们所对应的相关选项及具体算法都有所不同。在采用变步长类算法时,首先应该指定允许的误差限,包括相对误差限(Relative Tolerance)和绝对误差限(Absolute Tolerance),当计算过程中的误差超过该误差限时,系统将自动调整步长,步长的大小将决定仿真的精度。在采用变步长类算法时还要设置所允许的最大步长(Max Step Size),在默认值(Auto)的情况下,系统所给定的最大步长为(终止时间起始时间) /50。在一般情况下,系统所给的最大步长已经足够,但如果用户所进行的仿真时间过长,则默认步长值就非常大,有可能出现失真的情况,这时应根据需要设置较小的步长。在采用固定步长算法时,要先设置固定步长。由于固定步长算法的步长不变,所以此时不设定误差限,而多了一个模型类型(Tasking Mode for Periodic Sample Times)的选项,该选项包括 Auto(默认值)、SingleTasking(单任务和 MultiTasking(多任务)。单任务是指各模块的采样速率相同,不检测采样速率的传递;多任务是指在模型中模块具有不同的采样速率,同时检测模块之间采样速率的传递;默认值则根据模块的采样速率是否相同来决定采用单任务还是多任务。变步长和固定步长包含多种不同的具体算法。一般情况下,连续系统仿真应该选择 ode45 变步长算法,对刚性问题可以选择变步长的 ode15s 算法,离散系统一般默认选择固定步长的 discrete(no continuous states)算法,要注意在仿真模型中含有连续环节时不能采用该仿真算法,而可以采用诸如 4 阶 Runge-Kutta 法这样的算法来求解问题。 1.
文章目录 前言一、虚拟机是什么?二、虚拟机安装1.下载虚拟机软件:2.下载centos 系统镜像:3.虚拟机安装:3.1 关闭杀毒软件:3.2 重启后继续安装:3.3 修改vm 安装的位置:3.4 勾掉用户体验后下一步完成安装:3.5 创建虚拟机:3.5.1 创建虚拟机:3.5.2 安装系统:选择我们下载好的系统:3.5.3 命名虚拟机的名称和位置:3.5.4 设置虚拟机使用磁盘的大小和存储的方式:3.5.5 完成虚拟机的创建:3.5.6 选择中文输入:3.5.7 选择自动分区:3.5.8 设置root 用户的密码:3.5.9 重启centos 开始使用: 三、系统网络设置1.ping www.baidu.com:2. 添加nameserver :3. 查看网卡名称:4. 网卡启动配置:5. 重启网络: 四、总结: 前言 一、虚拟机是什么? 虚拟机是一种基于软件的虚拟计算机,可以在物理计算机上创建多个操作系统环境和应用程序运行环境的沙盒。虚拟机软件通过模拟计算机硬件和操作系统等资源,可以在一台物理计算机上设计和运行多个虚拟计算机。
虚拟机可以让用户在单个计算机上运行多个不同的操作系统,比如同时运行 Windows、Linux、MacOS 等。因为虚拟机软件创建的虚拟机提供了一个独立的操作系统环境、硬件环境和软件运行环境,所以不同虚拟机之间可以实现完全的隔离,安全性更高。
使用虚拟机的另一个好处是,可以提高资源的利用率。在一台物理服务器上,使用虚拟机软件可以分割为多个虚拟机,每个虚拟机可以运行不同的应用程序或服务,从而提高硬件资源的利用率,最大程度地节约硬件和人力成本。
虚拟机的应用范围非常广泛,例如在开发测试、应用测试、服务验证、互联网服务、数据中心等方面都有广泛应用。在云计算时代,虚拟化技术也是重要的基础技术之一。
二、虚拟机安装 1.下载虚拟机软件: 下载地址VMware Workstation Player :
https://customerconnect.vmware.com/cn/downloads/details?downloadGroup=WKST-PLAYER-1702&productId=1377&rPId=104735
2.下载centos 系统镜像: 下载地址:
https://mirrors.aliyun.com/centos/7/isos/x86_64/?spm=a2c6h.25603864.0.0.199c4511AakNSv
3.虚拟机安装: 3.1 关闭杀毒软件: 安装之前最好先关闭杀毒软件,否则有可能安装进程会被阻止,然后双击exe 开始安装;
3.2 重启后继续安装: 3.3 修改vm 安装的位置: 3.4 勾掉用户体验后下一步完成安装: 3.5 创建虚拟机: 3.5.1 创建虚拟机: 3.5.2 安装系统:选择我们下载好的系统: 3.5.3 命名虚拟机的名称和位置: 3.5.4 设置虚拟机使用磁盘的大小和存储的方式: 3.
信号与系统复习笔记——采样与通讯系统 采样定理 冲激串采样函数可表示为:
p ( t ) = ∑ n = − ∞ + ∞ δ ( t − n T ) p(t) = \sum_{n=-\infty}^{+\infty} \delta(t - nT) p(t)=n=−∞∑+∞δ(t−nT)
周期 T T T 称为采样周期,而 ω s = 1 T \omega_s = \frac{1}{T} ωs=T1 为采样频率。
对信号 x ( t ) x(t) x(t) 进行冲激串采样的结果为:
x p ( t ) = x ( t ) p ( t ) = ∑ n = − ∞ + ∞ x ( n T ) δ ( t − n T ) x_p(t) = x(t)p(t) = \sum_{n=-\infty}^{+\infty} x(nT) \delta(t - nT) xp(t)=x(t)p(t)=n=−∞∑+∞x(nT)δ(t−nT)
为了之后还能记得怎么处理我的经纬度数据,留下这个笔记
首先通过手持GPS设备获取了经纬度、时间、速度等原始数据,表格数据形式如下:
现要通过XLS数据生成GPX轨迹文件
import xlrd import pandas as pd import gpxpy import gpxpy.gpx # 加载XLS文件 workbook = xlrd.open_workbook(r'xls表格位置') sheet = workbook.sheet_by_index(0) # 假设数据在第一个工作表中 gpx = gpxpy.gpx.GPX() # 创建航线对象 track = gpxpy.gpx.GPXTrack() gpx.tracks.append(track) data = pd.read_excel(r'xls表格位置') print(data.columns) # 创建航线段 segment = gpxpy.gpx.GPXTrackSegment() track.segments.append(segment) # 逐行读取数据并生成GPX路点 for index, row in data.iterrows(): latitude = float(row[3]) longitude = float(row[2]) time = row[1] # 时间字段 speed = float(row[4]) # 速度字段 waypoint = gpxpy.gpx.GPXWaypoint(latitude, longitude, time=time) waypoint.
简介: 1.概述 一款工具,功能往往是很多的,细枝末节的地方也很多,实际的测试工作中,绝大多数场景会用到的也就是一些核心功能,根本不需要我们事无巨细的去掌握工具的所有功能。所以本文将用带价最小的方式讲解如何快速上手使用jmeter来进行压测。 JMeter,一款接口测试工具,是Java程序,需要JDK环境,建议使用JDK8或者JDK11。
1.概述 一款工具,功能往往是很多的,细枝末节的地方也很多,实际的测试工作中,绝大多数场景会用到的也就是一些核心功能,根本不需要我们事无巨细的去掌握工具的所有功能。所以本文将用带价最小的方式讲解如何快速上手使用jmeter来进行压测。
JMeter,一款接口测试工具,是Java程序,需要JDK环境,建议使用JDK8或者JDK11。
下载地址:
Apache JMeter - Download Apache JMeter
启动:
安装路径/bin/jmeter.bat(.sh)
2.测试计划、线程组、取样器 test plan:
测试计划,jmeter中的一个测试计划对应一个测试场景。
thread group:
线程组,jmeter中的一个线程组对应一个行为。一个行为可以理解为一个场景,可以是由多个接口组成的,比如下单,里面就可以包含扣减库存、生成订单等多个接口。
取样器:
可以理解为一次请求,jmeter支持多种类型的取样器,当然我们常用的是http的取样器。
三者的关系:
整个jmeter的使用其实就是建立一个测试计划,然后给这个测试计划下面配上各种需要的东西,比如线程组、监听器等等,
一个线程组包含多个取样器,一个取样器就是一个请求。线程组里面的每一条线程都会完整的从上到下顺序执行一遍该组下的取样器。
建立测试计划,添加线程组:
线程组添加取样器,对http接口的请求就添加http取样器:
一整套测试计划建好后,支持导出为文件,导出为文件后可以脱离开界面通过指令来运行整个测试计划:
3.调试运行 测试计划直接执行是不会有任何结果展示的,需要添加监听器(listener)来进行调试,查看中间结果。
一般使用view results tree,查看结果树的监听器,可以查看到运行结果。
一些核心参数的意思:
Connect Time:建立TCP连接的时间。
lantency:发出请求前到接收到第一个响应的时间。
loadtime:从发出请求前到接收完所有响应的时间。
Size in bytes:整个response报文的大小=header+body。
Headers size in bytes:response的header大小。
Body size in bytes:response的body大小。
4.请求默认值 请求默认值,即请求的缺省配置默认值。配置后一个测试计划中的所有请求都的配置缺省时都采用请求默认值中的配置。
5.流量录制 测试网页页面的时候http请求里面除了API,还杂糅着很多静态资源(html/js/css)的请求,到底请求这个页面发出了多少url?可以使用jmeter的流量录制功能,可以录制出某次访问里的所有http请求。这个功能在实际压测里用的比较少,这里只是提一句有这个功能,不做展开,具体要用的时候可以搜一下,怎么使用。
6.模拟时间间隔 使用定时器可以模拟时间间隔,定时器的作用范围是所在结点下的所有同级结点及其子结点。
定时器有多种,有些定时器不是固定时间间隔的,比如时间间隔满足高斯变化的高斯定时器等,具体的种类可以搜一下。
7.压力测试 运行指令:
真正的压力测试不使用图形界面来测试,因为图形界面作为中间层也会有性能损耗,而是直接使用命令行模式。
{base dir}\bin\jmeter -n -t XXX.jmx -l log.jtl
效果:
动态添加颜色 随机色
代码:
<div class="mt-10 firstTitle" v-show="pictureType != 'card' && pictureType != 'table' && pictureType != 'inventory'" > <i :class="[colorSystemShow ? 'el-icon-com-xiajiantou' : 'el-icon-com-youjiantou']" @click="colorSystem_before" class="c-pointer" ></i> <span class="ml-5">色板</span> <span class="c-pointer pull-right" @click="colorConfig">配置</span> <div v-show="colorSystemShow" class="mt-10 secondTitle colorSystem pl-5"> <div v-for="itemOut in colorList" style="height:20px;" class="mt-5"> <span v-for="itemIn in itemOut.value" :style="{background:itemIn}" style="display:inline-block;width:13.5px;height:20px;" ></span> </div> </div> </div> 组件:
<template> <el-dialog title="色板配置" :visible.sync="isColorConfigDialog" width="690px" :close-on-click-modal="false" :show-close="false" top="90px" > <div class="mainDiv"> <el-button class="
背景 要求指定的IP段才能访问主机的 3306 端口
安装iptables yum install -y iptables-services systemctl enable iptables service iptables start 添加IP段白名单 iptables -I INPUT -p tcp --dport 3306 -j DROP && \ iptables -I INPUT -m iprange --src-range 172.50.49.13-172.50.49.42 -p tcp --dport 3306 -j ACCEPT && \ iptables -I INPUT -m iprange --src-range 172.29.145.10-172.29.145.40 -p tcp --dport 3306 -j ACCEPT 三条命命令的含义
iptables -I INPUT -p tcp --dport 3306 -j DROP 禁止访问呢3306
iptables -I INPUT -m iprange --src-range 172.
应用(记录用户操作日志): 有时候我们需要处理一些请求日志,或者对某些方法进行一些监控,如果出现例外情况应该进行怎么样的处理,现在,我们从spring boot中引入AOP 1、开发准备
环境:idea、jdk 1.8、springboot、mysql 1.1 目录结构
└─src └─main ├─java │ └─com │ └─example │ └─log │ │ LogApplication.java │ ├─annotation │ │ Log.java │ ├─aspect │ │ LogAspect.java │ ├─common │ │ ├─context │ │ │ BaseContext.java │ │ │ CallBack.java │ │ │ SpringContextHolder.java │ │ ├─enums │ │ │ Action.java │ │ └─utils │ │ CloseUtil.java │ │ ExceptionUtil.java │ │ FileUtil.java │ │ ServletUtil.java │ ├─controller │ │ LogController.
1 安全运维 1.1 账户和登录安全 1.1.1 删除特殊用户和用户组 主要用userdel groupdel删除无用用户和组
一般需了解用户管理相关命令与选项用法,如usermod -s nologin userxxx
一般无用用户 adm,lp,sync,shutdown,halt,news,uucp,operators,games,gopher
一般无用组 adm,lp,news,games,dip,pppusers,popusers,slipusers
1.1.2 删除无用服务 chkconfig --pevel 345 bluetooth off
然后重启服务器
345 3表示支持nfs的多用户,5表示支持xwindows,4预留选项
1.1.3 密钥策略 一般有密码和密钥方式登录服务器,推荐密钥
先在本地生成密钥,然后将公钥追加到服务器用户目录下.ssh/authrized_keys的文件,即可单向登录
1.1.4 sudo使用与配置 给普通用户加提权权限
/etc/sudoers
文件的每行对应一个权限,格式如下
username hosts = cmd vars
四个参数分别为用户名,可访问的主机列表,cmd和cmd参数,例如
usera ALL = /bin/more /etc/shadow
userb ALL = NOPASSWD: /bin/more /etc/shadow
提权后普通用户执行提权命令会提示输入密码,此时密码不是root密码,而是用户的密码
userc ALL = (ALL) NOPASSWD: ALL
表示userc可获得root权限且不需要密码,su root _即可,且不需密码
1.1.5 修改系统登录欢迎信息 本地登录终端,终端提示信息源于/etc/issue
ssh/telnet登录时,终端提示信息源于metc/issue.net
每次登录终端都会有公告信息,公告信息源于文件etc/motd
1.2 远程访问与认证安全 1.
目录
一、消息队列 (message queue)
1、消息队列是什么
2、消息队列的优点
3、消息队列的模式
4、常用消息队列比较
二、kafka
1、kafka介绍
2、备份
3、基本概念
三、部署zookeeper集群
1、zookeeper介绍
2、zookeeper集群的部署
3、关于zookeeper集群的说明
四、 kafka集群的搭建
五、eflk数据流
appserver -->filebeat --> kafka --> logstash --> elasticsearch --> kibana
filebeat配置
logstash[消费者]配置
一、消息队列 (message queue) 1、消息队列是什么 1.消息队列是进程间通信或同一进程间不同线程的通信方式。
2.消息队列提供了异步通信协议。
3.消息的发送者和接收者不需要同时与消息队列交互,消息会保存在队列中, 直到接收者取回它。
4.每一个贮列中的纪录包含详细说明的数据, 包含发生的时间, 输入设备的种类, 以及特定的输入参数。
5.消息队列中间件是分布式系统中重要的组件。
消息队列主要解决应用耦合、异步处理、流量削锋等问题 当前使用较多的消息队列有RabbitMQ、RocketMQ、ActiveMQ、Kafka、ZeroMQ、MetaMq等, 而部分数据库如Redis、Mysql以及phxsql也可实现消息队列的功能。
2、消息队列的优点 解耦:在项目启动之初来预测将来项目会碰到什么需求, 是极其困难的消息系统在处理过程中间插入了一个隐含的、基于数据的接口层, 两边的处理过程都要实现这一接口这允许你独立的扩展或修改两边的处理过程, 只要确保它们遵守同样的接口约束
冗余:有些情况下, 处理数据的过程会失败除非数据被持久化, 否则将造成丢失消息队列把数据进行持久化直到它们已经被完全处理, 通过这一方式规避了数据丢失风险许多消息队列在把一个消息从队列中删除之前, 需要你的处理系统明确的指出该消息已经被处理完毕, 从而确保数据被安全的保存直到你使用完毕
扩展性:因为消息队列解耦了你的处理过程, 所以增大消息入队和处理的频率是很容易的, 只要另外增加处理过程即可不需要改变代码、不需要调节参数,扩展就像调大电力按钮一样简单
峰值处理:在访问量剧增的情况下, 应用仍然需要继续发挥作用, 但是这样的突发流量并不常见,如果为以能处理这类峰值访问为标准来投入资源随时待命无疑是巨大的浪费使用消息队列能够使关键组件顶住突发的访问压力, 而不会因为突发的超负荷的请求而完全崩溃
可恢复性:系统的一部分组件失效时, 不会影响到整个系统即使一个处理消息的进程挂掉, 加入队列中的消息仍然可以在系统恢复后被处理
顺序保证:在大多使用场景下, 数据处理的顺序都很重要大部分消息队列本来就是排序的, 并且能保证数据会按照特定的顺序来处理如Kafka能保证一个Partition内的消息的有序性
四则运算计算器是一款功能简单但极为实用的应用程序。在本篇文章中,我们将使用C#语言为大家演示如何编写一个基于控制台的四则运算计算器程序。
**1. 程序设计思路** 在设计控制台四则运算计算器程序时,我们需要确定程序的基本功能,包括输入、运算符选择和输出。我们可以采用逐个读取用户输入的方式,再根据输入的数据类型、运算符类型等进行数据处理和计算。
具体的程序设计思路如下:
1. 获取用户输入的数字和运算符;
2. 根据运算符进行运算,得到计算结果;
3. 输出计算结果。
**2. 程序实现**
2.1 获取用户输入
在C#中,我们可以使用Console.ReadLine()函数逐行读取用户输入。对于输入的字符串,我们可以使用正则表达式库来进行分割。
```C#
// 首先以空格进行分割,得到数字和运算符
string[] inputs = Console.ReadLine().Split(" ");
// 如果分割后字符串数组的长度不为3,说明用户输入有误
if (inputs.Length != 3)
{
Console.WriteLine("输入有误!");
return;
}
// 分别获取输入的数字和运算符
int num1 = int.Parse(inputs[0]);
int num2 = int.Parse(inputs[2]);
string op = inputs[1];
```
2.2 根据运算符进行计算
有了用户输入的数字和运算符,我们就可以进行四则运算了。根据运算符的不同,我们可以通过算术运算符来计算结果。
```C#
// 根据运算符进行计算
int result = 0;
switch (op)
{
case "+":
result = num1 + num2;
目录
前言
一、准备工作
1、工具准备
2、操作系统
二、Flask项目搭建
1.新建项目文件夹
2.搭建虚拟环境
(1)在终端创建虚拟环境
(2)激活虚拟环境
3.安装Flask
(1)先退回到项目文件夹下
(2)输入命令安装Flask
4、新建Flask需要的文件
(1)app.py文件
(2)创建templates文件夹
(3)创建static文件夹 5、运行项目
(1)输入命令,默认端口号是5000
(2) 运行结果
总结
前言 使用vs code搭建Flask项目的环境,以及项目的创建。
一、准备工作 1、工具准备 vs code软件python软件 2、操作系统 win 11 二、Flask项目搭建 1.新建项目文件夹 新建Demo1文件,然后用vs code 打开 2.搭建虚拟环境 (1)在终端创建虚拟环境 使用快捷键ctrl+shift+~,调出vscode的终端,然后输入命令
python -m venv venv (2)激活虚拟环境 首先进入到'venv/Scripts' 路径下
cd 'venv/Scripts'
然后输入以下命令:
./activate
这样就激活了虚拟环境。
3.安装Flask (1)先退回到项目文件夹下 cd..
cd..
(2)输入命令安装Flask pip install flask
然后等待它安装成功就可以了。
4、新建Flask需要的文件 (1)app.py文件 在项目根目录下新建app.py文件,然后写入如下代码
from flask import Flask
app=Flask(__name__)
文章目录 1.sendMessage方法发送消息2.invokeOneway单向发送2.1 invokeOnewayImpl单向调用 3.sendMessageSync同步发送3.1 invokeSync同步调用3.1.1 invokeSyncImpl同步调用实现3.1.2 processSendResponse处理响应结果 4.sendMessageAsync异步发送消息4.1 invokeAsync异步调用4.1.1 invokeAsyncImpl异步调用实现 4.2 onExceptionImpl异常处理 5.NettyClientHandler处理服务端消息5.1 processResponseCommand处理响应5.1.1 executeInvokeCallback执行回调函数5.1.2 putResponse存入响应 6.总结 1.sendMessage方法发送消息 DefaultMQProducerImpl#sendKernelImpl() -> MQClientAPIImpl#sendMessage()
MQClientAPIImpl#sendMessage : 异步、单向、同步发送模式都会调用MQClientAPIImpl#sendMessage方法发送消息。
首先构建发送消息命令对象RemotingCommand, 此时会判断是否需要更换轻量级消息头, 如果sendSmartMsg属性为true或者为批量消息的话, 则使用轻量头。根据发送模式执行不同的发送逻辑, 单向发送模式调用NettyRemotingClient#invokeOneway, 异步发送调用MQClientAPIImpl#sendMessageAsync, 同步发送调用MQClientAPIImpl#sendMessageSync。 /** * MQClientAPIImpl的方法 * 同步、异步、单向消息的最终发送消息的方法 * * @param addr brokerAddr * @param brokerName brokerName * @param msg msg * @param requestHeader requestHeader * @param timeoutMillis 剩余超时时间 * @param communicationMode 发送模式 * @param sendCallback 发送回调函数 * @param topicPublishInfo topic信息 * @param instance MQClientInstance * @param retryTimesWhenSendFailed 异步发送失败时的重试次数,默认2 * @param context 发送消息上下文 * @param producer DefaultMQProducerImpl * @return * @throws RemotingException * @throws MQBrokerException * @throws InterruptedException */ public SendResult sendMessage( final String addr, final String brokerName, final Message msg, final SendMessageRequestHeader requestHeader, final long timeoutMillis, final CommunicationMode communicationMode, final SendCallback sendCallback, final TopicPublishInfo topicPublishInfo, final MQClientInstance instance, final int retryTimesWhenSendFailed, final SendMessageContext context, final DefaultMQProducerImpl producer ) throws RemotingException, MQBrokerException, InterruptedException { long beginStartTime = System.
介绍
这里是小编成长之路的历程,也是小编的学习之路。希望和各位大佬们一起成长!
以下为小编最喜欢的两句话:
要有最朴素的生活和最遥远的梦想,即使明天天寒地冻,山高水远,路远马亡。
一个人为什么要努力? 我见过最好的答案就是:因为我喜欢的东西都很贵,我想去的地方都很远,我爱的人超完美。因此,小编想说:共勉!
本篇文章是小编记录Linux的系统学习
目录
一、负载均衡
1、什么是负载均衡?
2、常见的nginx负载均衡的方式有哪些?
二、负载均衡的实现
1、需求
2、步骤
1、配置多台tomcat应用服务器(小编是在window下一台,linux下一台)
2、在ngnix中增加配置/etc/nginx/sites-available/default(还可在nginx的根目录下的nginx.conf中配置)也可以配置两个及以上的服务如下代码:
3、nginx负载均衡的参数:
4、让配置生效,更新配置
5、访问服务
一、负载均衡 1、什么是负载均衡? 负载均衡建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。
负载均衡,英文名称为Load Balance,其意思就是分摊到多个操作单元上进行执行,例如Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。
2、常见的nginx负载均衡的方式有哪些? Nginx提供了多种负载均衡方式,以下是常见的几种方式:
1. 轮询(round-robin):默认的负载均衡策略,即将请求依次分配到不同的后端服务器上。当请求分配到最后一个后端服务器时,统计数据清零,重新从第一个后端服务器开始分配。
2. IP哈希(ip_hash):根据客户端的IP地址进行哈希计算,将同一客户端的请求分配到同一后端服务器上。这种方式可以保证同一客户端的所有请求都会被分配到同一后端服务器上,可以解决某些应用场景下的问题。
3. 最少连接(least_conn):将请求发送到当前连接数最少的后端服务器上。这种方式可以让负载均衡算法选择处理请求最快的服务器,提高系统响应速度。
4. 加权轮询(weight):根据服务器的权重进行请求分配,权重越高的服务器能够处理更多的请求。这种方式可以根据服务器的处理能力分配请求,提高整个系统的性能。
5. 加权最少连接(least_conn + weight):将最少连接方式与加权方式结合使用,基于连接数和服务器权重进行请求的分配,能够选择最快的和处理能力最强的服务器。
当然,Nginx负载均衡还可以设置一些高级选项,如:健康检查、慢启动、最大失败数等。这些高级选项可以保证负载均衡的稳定性和可靠性,提高应用系统的可用性。
总之,Nginx提供了多种负载均衡方式,包括轮询、IP哈希、最少连接、加权轮询和加权最少连接等。根据不同的应用场景和要求,选择合适的负载均衡方式和参数组合,可以实现灵活、高效、稳定的负载均衡。
二、负载均衡的实现 1、需求 nginx作为负载均衡服务器,用户请求先到达nginx,再由nginx根据负载配置将请求转发至tomcat服务器。
eg:
nginx负载均衡服务器:IP地址1:80
tomcat1服务器:http://ip地址2:80
tomcat2服务器:http://IP地址1:8080
2、步骤 1、配置多台tomcat应用服务器(小编是在window下一台,linux下一台) 2、在ngnix中增加配置/etc/nginx/sites-available/default(还可在nginx的根目录下的nginx.conf中配置)
也可以配置两个及以上的服务如下代码: 下面的代码只是一个示例,具体可以根据自己的情况去配置
upstream tomcatserver1 { # 第一台服务器 upstream tomcatserver1 { server 192.168.0.126:8080; server 192.168.0.126:8082; } # 第二台服务器 upstream tomcatserver2{ server 192.
前言 在一个群里面看到一个人问,do-while(0)语句有什么用?do-while(0)这个程序最终结果不应该就是程序只跑一次,那么写和不写有什么区别呢?
do-while(0)在复杂宏定义上的优点 为什么需要复杂宏 (1)在讲解do-while(0)在复杂宏定义上的优点前,我先介绍一下复杂宏的好处。
(2)当我们看到一个宏定义非常复杂的时候,我们很自然而然的会想到,为啥不让他变成一个函数呢?在宏定义里面搞到这么花里胡哨的,不如直接定义一个函数来的方便。
(3)当我带着这么问题去询问了交流群之后,一个大佬马上给出了回复。
<1>他说他当年一个项目8位单片机,函数都不敢深入调用,好多都是写的宏函数。因为资源有限。
<2>大佬介绍到,他哪一款单片机,硬件堆栈,好像就7层,中断预留两层,有些c标准函数用两层堆栈,自己写的就限制在3-4层左右。因为堆栈的有限,怕因为函数的深入调用如果过于频繁或递归层数过深,可能导致栈空间不足,发生堆栈溢出。当栈空间不足以容纳新的栈帧时,程序会崩溃或异常终止。
<3>所以他们当年都是这样写代码
优点介绍 (1)当我们在编写业务逻辑的时候,可能可能需要定义一个比较复杂的宏。如下
#define fun printf("hello"); printf("world") int main() { fun; return 0; } (2)在这个宏的基础上,我们增加一个判断语句,就会发现问题所在。
/******* c文件 *******/ #define fun printf("hello"); printf("world") int main() { int a=0; if (a == 0) fun; else ... return 0; } /******* 预处理之后 *******/ int main() { int a=0; if (a == 0) printf("hello"); printf("world"); else ... return 0; } (3)通过上面的代码,我们明显的发现了。如果是在if语句中,执行这个宏,会发现第二个语句不会包含在if语句中。这样就会导致,因为 if 分支后有两个语句,导致 else 分支没有对应的 if,编译失败。
public class PDFUtils { //校验license private static boolean judgeLicense() { boolean result = false; // 21.6 try { Class<?> aClass = Class.forName("com.aspose.words.zzXyu"); java.lang.reflect.Field zzYAC = aClass.getDeclaredField("zzZXG"); zzYAC.setAccessible(true); java.lang.reflect.Field modifiersField = zzYAC.getClass().getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(zzYAC,zzYAC.getModifiers() & ~Modifier.FINAL); zzYAC.set(null, new byte[] {76,73,67,69,78,83,69,68}); result = true; } catch (Exception e) { e.printStackTrace(); } return result; } /** 根据byte数组,生成文件 **/ public static void getFile(byte[] bfile, String filePath,String fileName) { BufferedOutputStream bos = null; FileOutputStream fos = null; File file = null; try { File dir = new File(filePath); if (!
目录
关于Spring MVC框架
Spring MVC框架的依赖项
使用Spring MVC框架接收请求
关于@RequestMapping注解
关于RESTful
关于@RequestParam注解
@RequestParam注解是添加在方法的参数上的,它的作用主要有: 其它
关于Spring MVC框架 MVC:Model + View + Controller Spring MVC框架主要解决了接收请求、响应结果及相关问题(例如处理异常等),即主要关注C的问题,在不是前后端分离的项目,还关心V的问题,但是,并不关心M的问题。 Model:模型,数据处理的流程和规则。具体表现为service和mapper的整合。
Spring MVC框架的依赖项 Spring MVC框架的基础依赖项是:spring-webmvc 在Spring Boot中,使用Spring MVC框架应该添加依赖项:spring-boot-starter-web 使用Spring MVC框架接收请求 应该创建控制器类,并在控制器类上添加@Controller注解,在Spring MVC框架中,只有添加此注解的类才是控制器类!
默认情况下,在Spring MVC框架中,控制器处理请求的结果(方法的返回值)将被视为“视图组件的名称”,当在处理请求的方法上添加@ResponseBody注解后,返回的结果才会被视为“响应到客户端的数据”,@ResponseBody注解还可以添加在控制器类上,表示此类中所有处理请求的方法的返回结果都是“响应到客户端的数据”,这种做法称之为“响应正文”,或者,也可以将控制器类上的注解改为@RestController,它是@Controller和@ResponseBody的组合注解!
包括处理异常的“全局异常处理器类”,需要添加的其实是@ControllerAdvice注解,添加此注解的类中的特定方法(例如处理异常的方法)将可以作用于每次处理请求的过程中,但是,默认情况下,仍不是“响应正文”的,所以,当处理异常需要响应正文时,需要在处理异常的方法上添加@ResponseBody注解,或在全局异常处理器的类上添加@ResponseBody注解,或将@ControllerAdvice改为@RestControllerAdvice。
在控制器类上,可以自定义方法用于处理请求,关于这些方法:
访问权限:应该是public
返回值类型:当响应正文时,可自行将需要响应的数据属性封装在自定义类中,使用自定义类作为返回值类型
当使用自定义类型进行响应正文时,需要:
需要添加jackson-databind依赖项,在spring-boot-starter-web中已经包含
需要启用Spring MVC的注解增强,如果使用XML配置(早些年用的多),需要添加<annotation-driven/>,如果使用配置类进行配置,需要在配置类上添加@EnableWebMvc注解,否则,响应时会出现406错误,在Spring Boot项目不需要手动配置
方法名称:自定义
参数列表:按需添加,且各参数不区分先后顺序,可以将各请求参数逐一作为参数列表中的参数,也可以将多个请求参数封装到自定义类型中,使用自定义类型作为方法参数列表中的参数,还可以按需添加HttpServletRequest、HttpServletResponse、HttpSession等,在使用其它技术框架后,还可以按需添加其它参数,例如结合@AuthenticationPrincipal注解添加Spring Security的当事人
抛出异常:理论上,处理请求的方法不应该处理异常,而应该抛出,进而交由全局异常处理器进行处理
所有处理请求的方法都必须添加@RequestMapping系列(还有GetMapping,PostMapping等)的某个注解,通过这些注解来配置请求路径。
关于@RequestMapping注解 @RequestMapping注解的主要作用是配置请求路径,通常,在类上应该配置此注解,例如: @RestController @RequestMapping("/admin") public class AdminController {} 在方法上,建议使用限制了请求方式的某个基于@RequestMapping的注解,例如:
@RestController @RequestMapping("/admin") public class AdminController { @PostMapping("/login") public JsonResult login() { // .
一、引言 在不更改代码情况下,使用nginx拦截请求参数token,通过token长短转发到不同应用。可使用nginx_lua 实现。
二、处理方案 2.1 前置要求 nginx安装lua模块,也可直接使用OpenResty(通过Lua拓展nginx的web平台);
下载地址: http://openresty.org/cn/
2.2 编写demo.lua脚本 -- 1、token可通过url和请求头传递 -- 2、新程序token是jwt,旧程序token是原生的security oauth2 生成的uuid -- 分別从请求头、url获取token -- 获取body参数 -- 可使用ngx.req.read_body()和 ngx.req.get_post_args() -- 1、从url中获取token,从请求头获取token,替换Bearer local param = "" if(ngx.var.arg_token ~= nil) then param = ngx.var.arg_token elseif(ngx.var.http_Authorization ~= nil) then param= string.gsub(ngx.var.http_Authorization, "Bearer ", "") end -- 根据token长度 转发 if (param ~= nil and string.len(param) > 40 ) then ngx.log(ngx.ERR,"token--new--send " ..param) return ngx.exec("/new", {token= param}) else ngx.
事先声明,本人所写代码用于学习,原代码撰写者@张爱烂(同时也是我的室友)
以后也会发表一些我抄写的代码,也不是为了给谁看,就当作一种学习的证明吧
#数据准备 D_list=[]#测站距离 obs_degree_list=[]#观测角的弧度 import math def dms_to_radians(degree): #获取度分秒 degrees_str=degree[0] minutes_str=degree[1] seconds_str=degree[2] #转化为数字 degrees=float(degrees_str) minutes=float(minutes_str) seconds=float(seconds_str) #计算弧度 radians=math.radians(degrees+(minutes/60)+(seconds/3600)) return radians n=8#测站数 user_input="T"#确定观测角方向,输入T(左角)或F(右角) with open("C:\\Users\\hp\\Desktop\\example.txt","r") as f: #读取第一行数据 first_line = f.readline().strip() #读取第二行数据 second_line = f.readline().strip() #读取第三行数据以后的数据 for line in f: items_list=[]#储存观测角 v_degree=[]#储存竖直角 #按分割符拆分每一行数据 data=line.strip() data=data.split(',') print(data) #读取前三个元素和第四个元素 item1,item2,item3,item4=data[0],data[1],data[2],data[3] items_list.append(item1) items_list.append(item2) items_list.append(item3) obs_degree_list.append(dms_to_radians(items_list)) D_list.append(float(item4)) a12=[] a12=first_line.split(',') print("起始方位角:",a12) a12=dms_to_radians(a12) J_x_1,J_y_1=second_line.split(',') J_x_1,J_y_1=float(J_x_1),float(J_y_1) print("起始点测站坐标:",J_x_1,",",J_y_1) print("测站距离:",D_list) print("观测角弧度:",obs_degree_list) b_list=obs_degree_list #计算方位角闭合差 sum_b=sum(b_list) f_b=sum_b-((n-2)*math.pi) print("\n方位角闭合差为:",f_b) f_b_limit=(400/3600)*(math.pi/180)*math.sqrt(n) print("理论限差为:",f_b_limit) f_b_abs=abs(f_b) if(f_b_abs<f_b_limit): print("
vue中实现input禁止粘贴 部分业务场景下,会出现不允许用户在input输入框中进行粘贴操作的情况,例如:密码输入框,或者一些其他的敏感信息,禁止粘贴。
实现一 要禁止粘贴操作在 el-input 组件中,可以结合使用 @paste 事件和 preventDefault 方法。
下面是一个简单的示例:
<template> <div> <el-input v-model="inputValue" @paste="handlePaste"></el-input> </div> </template> <script> export default { data() { return { inputValue: '' }; }, methods: { handlePaste(event) { event.preventDefault(); // 阻止粘贴操作 // 或者可以执行其他的处理逻辑 } } }; </script> @paste 监听了 el-input 组件的粘贴事件。在 handlePaste 方法中,使用 event.preventDefault() 阻止了默认的粘贴行为,从而禁止了粘贴操作。您还可以根据需要在 handlePaste 方法中执行其他的自定义处理逻辑。
实现二 el-input 组件上使用原生的 @paste 事件,并且同时结合 .capture 和 .prevent 修饰符来阻止粘贴操作
简单示例:
<template> <div> <el-input v-model="inputValue" @paste.native.capture.prevent="handlePaste"></el-input> </div> </template> <script> export default { data() { return { inputValue: '' }; }, methods: { handlePaste(event) { // 处理粘贴事件 } } }; </script> 上述示例中,我们在 @paste 事件上使用了 .
这里写目录标题 一、Simulink 操作基础1. Simulink 的启动与退出1.1 Simulink 的启动1.2 模型文件的打开1.3 Simulink 的退出 2. Simulink 仿真初步2.1 模型元素2.2 仿真步骤2.3 简单实例 二、系统仿真模型的建立1. Simulink 的基本模块2. 模块操作2.1 添加与删除模块2.2 选取模块2.3 复制模块2.4 模块外形的调整2.5 模块名的处理 3. 模块的连接3.1 连接两个模块3.2 模块间连线的调整3.3.连线的分支3.4.标注连线 4. 模块的参数和属性设置4.1 模块的参数设置4.2 模块的属性设置 一、Simulink 操作基础 Simulink 是 MATLAB 的重要组成部分既适用于线性系统,也适用于非线性系统,既适用于连续系统,也适用于离散系统和连续与离散混合系统。既适用于定常系统,也适用于时变系统。 1. Simulink 的启动与退出 1.1 Simulink 的启动 在安装 MATLAB 的过程中。若选中了 Simulink 组件,则在 MATLAB 安装完成后,Simulink 也就安装好了。如果需要,可以直接启动 Simulink,步骤如下。(1) 在 MATLAB 的命令行窗口输入 Simulink 命令,或选择 MATLAB 主窗口 “主页" 选项卡,单击 SIMULINK 命令组中的 Simulink 命令按钮,或选择 MATLAB 主窗口 “主页"
【编译原理】计算器实现(C语言) 题目要求简单分析(1)读文件(2)词法分析(3)语法分析(4)后缀表达式求值 总结 这几天编译原理课留了个编写一个简单的计算器,要求能够检查错误并进行计算。其实也就是完成词法分析,语法分析,再完成一个后缀表达式的计算就好了。
这里找到了一个比较简单的方法,这里记录一下。
题目要求 简单分析 整个程序其实整体上大致分成四部分去做
1.读文件存储内容(这里的文本是以字符的形式存储的)
2.词法分析,把字符拆分成一个个的token
3.语法分析,对拆分的token进行分析,确定有无错误
4.后缀表达式求值,在确认格式无误后进行后缀表达式求值并输出
(1)读文件 readFile()函数完成了读入字符串到str数组中保存起来,方便后续操作,在这里处理了一个结尾是否为“ . “的错误,比较简单没什么好说的。
下面是具体函数 readFile。
unsigned long readFile(char *filePath, char str[]) { FILE *fp = fopen(filePath, "r");//打开文件 if (fp == NULL) { printf("打开文件出错,请确认文件存在当前目录下!\n"); exit(0); } unsigned long i; i = fread(str, 1, MaxLen, fp); if (i >= MaxLen) { printf("文件过大!请重新输入一个更小的文件。\n"); exit(1); } if (str[i - 1] != '.') { printf("Error, Please end up with \".\"\n"); is_error = 1; } str[i] = '\0'; fclose(fp); return i; } (2)词法分析 词法分析函数Scaner()这里的词法分析生成token,如果了解过一些编译原理词法分析的内容的话,这里的这个方法其实是有很多简化的,他其实只处理并储存了数字,标识符(变量名、int 、float) 对于其它的标点,运算符等符号其实都没有进行处理,只是将其分割但是没有保存。
Python 的字符串处理, 实现一个朴实无华的四则运算计算器,批量计算小学生四则运算表达式
方法一:
# -*- coding: UTF-8 -*- import re def naive_calc(code): # 按行分割代码 lines = code.strip().split('\n') # 匹配四则运算表达式的正则表达式 pattern = r'\d+(\.\d+)?\s*[\+\-\*/]\s*\d+(\.\d+)?' # 遍历每行代码,并计算四则运算表达式的值 for line in lines: # 匹配四则运算表达式 match = re.search(pattern, line) if match: # 获取四则运算表达式 expr = match.group() # 计算表达式的值 value = eval(expr) # 将表达式替换为计算结果 line = line.replace(expr, str(value)) # 打印代码 print(line.strip()) def test(): code = ''' 1+2 3+4 5-3 4*3 10/2 ''' naive_calc(code) if __name__ == '__main__': test() 该代码实现了一个简单的四则运算计算器,可以批量计算小学生四则运算表达式。具体实现过程如下:
前端接收后端传递的数据结构为
[{total=84, projectName=新增自动消毒点卡机项目}]
该数据结构并不是json形式,所以需在后端对数据结构处理,处理成标准的json形式
List<Map<String, Object>> resHeadMap;
//调用第三方框架进行json处理
JSON.toJSON(resHeadMap)
重新接收后的数据结构为
[{"projectName":"新增自动消毒点卡机项目","total":84}]
再次在前端调用js函数就可以直接转化
JSON.parse(resHeadMap)
文章目录 简介os.systemos.popensubprocess.Popen()参考文献 简介 在python中,调用外部命令行(linux中的shell、或者windows中的cmd)来执行指令,常用的有三种方式:
os.system(‘pwd’);os.popen()subprocess.Popen() os.system 是os模块中最基础的部分,其他的方法一般是在该方法的基础上衍生来的。
每一条os.system指令在执行时,都会创建一个子进程在系统上来执行命令,子进程的执行结果是无法影响主进程的;
上述原理会导致当需要执行多条命令行的时候会得不到想要的结果,比如说:
import os os.system('cd /home/xxx/') os.mkdir('1.txt') 执行后会发现txt文件没有创建在/home/xxx/文件夹,而是创建在了本地,因为多条命令是独立的。
如果为了保证system执行多条命令可以成功,那么多条命令需要在一个os.system中执行,但需要用特殊的分隔符将它们隔开,如:
import os os.system('cd /home/xxx/ && mkdir 1.txt') os.system('cd /home/xxx/ ; mkdir 1.txt') 分号表示,这些命令会顺序执行下去;
&&表示,顺序执行,遇到执行错误的命令停下;
||表示,顺序执行,遇到执行成功的命令停止,后面不再执行;
os.system还有一个缺点,就是它的返回值只有0(成功),1,2。他对pwd等指令是会打印出执行结果,但是这个结果是内部打印出的,不是以返回值的形式打印出的,我们根本拿不到。比如说:
import os a=os.system('pwd') print(a) 输出:
/home/ttss 0 如果无法忍受这个问题,那么可以考虑使用os.popen()
os.popen os.popen()是打开一个管道来执行命令,并将命令的执行结果写入一个文件对象作为返回值。
调用格式:
os.popen(command, mode, bufsize) command是待执行命令,后面两个命令可选;
mode,指示模式权限,r或者w,默认是r;
bufsize,指明了文件需要的缓冲大小。0表示无缓冲,1表示行缓冲;其他正值表示使用参数大小的缓冲,以字节为单位;负值表示使用系统的默认值。可以使用默认
import os a=os.popen('pwd', 'r').readlines() print a # 输出: # ['/et/ttss\n'] 我们可以对返回的文件对象做继续操作。
这里需要注意两个地方:
关闭文件对象;设置阻塞 返回的文件对象是需要关闭的,因此规范的写法是在with语句里使用os.popen
with os.popen(command, 'r') as p: r = p.
1 下载AdBlock插件 AdBlock插件下载地址
2 解压缩 3 chrome添加扩展插件 1 文件夹打开到crx后缀的扩展文件
2 chrome右上角选择设置》扩展程序》进入扩展程序界面
3 右上角打开开发者模式
4 将刚刚crx扩展文件直接拖拽到扩展程序界面,成功添加
4 屏蔽百度热搜 方法一: 1 进到有百度热搜的界面
2 空白处右键》AdBlock——…》隐藏此页面上的内容
3 根据①处提示,鼠标移动确定百度热搜的位置,为蓝色框选区域,然后点击,成功选择,然后按提示点确定,完成百度热搜的屏蔽
方法二: 1 进到有百度热搜的界面
2 鼠标移到百度热搜那里》右键》检查》出现右侧网页布局代码》标蓝处为刚刚百度热搜的位置》鼠标一行行代码上移,边观察左侧百度热搜蓝色区域,直到蓝色区域第一次选中整个百度热搜》找到这行代码对应的class的值 FYB_RD》记下来
3 浏览器右上角点击扩展图标》点击AdBlock插件的选项》进入选项界面,在自定义一栏中》点击编辑》在编辑框中添加一行过滤规则》www.baidu.com##DIV[class=“FYB_RD”]》保存 (直接复制这行的话需要注意双引号是不是被改成了中文双引号,是的话需要改成英文双引号,不然不生效)
www.baidu.com##DIV[id="s-hotsearch-wrapper"][class="s-isindex-wrap s-hotsearch-wrapper"] www.baidu.com##A[class="undertips-link c-font-special"][href="https://www.baidu.com/s?wd=%E9%AB%98%E8%80%83&sa=ire_dl_gh_logo_texingwzl&rsv_dl=GK_PC_2023_index_tips"] www.baidu.com##DIV[class="FYB_RD"] 注:FYB_RD 就是刚刚上面记下来的class值,##的前面是网站的域名
在Python中,endswith() 函数用于检查字符串是否以指定的后缀结尾。当使用 endswith() 函数时,括号的使用方式会影响参数的类型。
使用单括号 ():
当传递给 endswith() 的参数是一个字符串时,你应该使用单括号。例如:
filename.endswith('.jpg') 使用双括号 (()):
当传递给 endswith() 的参数是一个元组时,你需要使用双括号。这样可以将多个后缀作为元组的元素传递给函数。例如:
filename.endswith(('jpg', 'gif', 'png')) 总结一下:
如果你想检查一个后缀,使用单括号加上后缀字符串;如果你想同时检查多个后缀,使用双括号来创建一个包含所有后缀的元组。
#!/bin/bash E_WRONG_DIRECTORY=73 clear TargetDirectory=/opt cd $TargetDirectory echo "Deleting stale files in $TargetDirectory." if [ "$PWD" != "$TargetDirectory" ];then echo "Wrong directory!" echo "In $PWD,rather than $TargetDirectory!" echo "Bailing out!" exit $E_WRONG_DIRECTORY fi rm -rf * rm -rf .[A-Za-z0-9]* echo echo "Done." echo "Old files deleted in $TargetDirectory." echo exit 0
变量命名是任何编程语言的重要部分,正确的变量命名可以帮助提高代码的可读性和可维护性。以下是一些常见的变量命名规则:
唯一性:每个变量都应该有一个唯一的名字,以区别于其他变量。语义性:变量名应当能够清晰地反映出其储存的数据类型或用途,例如,username就比u或x要好。一致性:如果你有一种命名变量的约定(例如使用小驼峰命名法),那么你应当在所有地方都一致地遵循这个约定。避免使用语言保留字:语言保留字,比如for、if等,有特殊的含义,不能用作变量名。 针对具体的编程语言,可能会有特殊的变量命名规则。例如:
在JavaScript,Python,Ruby等语言中,变量名通常用下划线(_)或者驼峰命名法进行连接,例如myVariable或my_variable。在Python中,变量名的开头可以是一个下划线(_),例如_myVariable,这有特殊的含义,表示这个变量是“私有的”或者“保护的”。在Java,C#等语言中,变量名通常使用驼峰命名法,例如myVariable,并且类的名称首字母通常大写,例如MyClass。 注意,这些只是一般性的规则和指导原则,具体的规则可能会因项目、团队、公司或编程语言的规定而有所不同。总的来说,清晰和一致的命名是最重要的。
什么是驼峰命名法 峰命名法(Upper Camel Case)。
小驼峰命名法(lower camel case):第一个单词以小写字母开始,第二个单词的首字母大写。例如:firstName、lastName。
大驼峰命名法(Upper Camel Case),也被称为Pascal命名法:每一个单词的首字母都采用大写字母。例如:FirstName、LastName。
驼峰命名法主要用于命名变量、函数或类。不同的编程语言和不同的项目可能会有不同的约定,例如,Java中的变量和函数常常使用小驼峰命名,而类名使用大驼峰命名;JavaScript中也常常使用小驼峰命名法。总的来说,关键是保持一致性和清晰性。
前言
关于printf函数和fputc函数联系和区别
联系:
1.共同目标:
printf 函数和 fputc 函数都用于将字符输出到指定的输出流中。
2.字符输出:
两个函数都可以用于输出一个字符,但在实际使用时,printf 函数通常用于输出格式化的数据,而 fputc 函数更常用于单个字符的直接输出。
区别:
1.功能差异:
printf 函数提供了更高级别的功能,可进行格式化输出、数值转换、对齐等操作。而 fputc 函数仅仅将单个字符写入到指定的输出流中。
2.参数类型:printf 函数接受格式化字符串和可变参数列表作为参数,因此可以输出多个不同类型的数据。而 fputc 函数接受一个字符和指向输出流的指针作为参数。
3.使用场景:由于 printf 函数提供了丰富的格式控制和数据转换功能,通常用于日常的输出和调试。而 fputc 函数更适合在特定情况下,直接将单个字符输出到指定设备或文件中。
为什么在stm32中要重定向printf函数?
在STM32微控制器中,printf 函数是用于将格式化的字符串输出到标准输出的函数。然而,默认情况下,STM32芯片并没有直接连接一个用于标准输出的终端设备,如串口或LCD显示屏。因此,为了使用 printf 函数来输出调试信息或结果,需要对其进行重定向。
====================================================
其实在printf函数内部来说,是封装了一个fputc函数来进行字符输出操作
所以这就是本节内容,如何在stm32中重定向printf,就是重定向fputc函数,本节使用串口实现,直接看代码实现
直接在你写的usart.c中添加即可
//重定向fputc函数 int fputc(int ch, FILE *f) //两个标准参数 { //将要发送的数据通过串口1发送出来(可以用电脑上的串口调试软件接收) USART_SendData(USART1, ch); //等待发送是否完成 while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET); return ch; } 如何找到这个函数和函数详解如下:
以下是关于STM32F4芯片给的寄存器手册,具体查找为何要这样重写
根据上图,我已经把为何重定向和如何重定向,以及重定向函数参数都做了仔细解读
使用:
1.直接在main函数直接使用printf函数即可(其他地方也可以使用,注意添加头文件)
int main(void) { Usart1_Init(); while(1) { //添加好stdio.h头文件之后,就可以正常使用printf函数了,方便以后调试 printf("你好,热爱代码陌生人!\n"); delay_ms(1000); } 2.
😉博主:初映CY的前说(前端领域) ,📒本文核心:vue文件怎么给DOM元素加上一个类
项目场景: 在前端页面逻辑操作中通常是存在click事件,添加点击效果是为了让页面操作起来更加的有操作性与互动性,那么有什么方式可以实现当我点击自动地为当前的DOM元素添加上一个属于它的类/或多个?
博主经常用判断是否点击当前项的地方,当我在页面上有点击某处,某处就高亮显示,其他取消高亮效果。
前言 DOM介绍
DOM是指文档对象模型(Document Object Model),是一种对于XML或HTML文档的内容进行抽象化和规范化的方法。DOM将整个文档视为一个树型结构,树的每个分支都表示文档中的一个元素,从而可以通过编程的方式来访问和修改文档的内容。
DOM可以通过JavaScript来访问,并且可以通过JavaScript来改变HTML或XML文档的结构、样式和内容。具体来说,DOM可以让开发者通过代码来增加、修改或删除HTML或XML文档中的元素、属性和文本,从而实现对网页的动态操作和交互。
在前端开发中,DOM是非常重要的一部分,因为它可以帮助开发者实现对网页的动态操作和交互,从而提高用户体验。同时,也可以通过DOM来实现一些比较复杂的功能,例如表单验证、数据检索、数据筛选和展示等。
DOM说白了就是我们在页面上看到的由HTML标签解析后的产物
v-bind介绍
v-bind是Vue.js提供的一个指令,用于动态绑定属性。它可以绑定的属性包括class、style、src、href等。通过v-bind指令,可以将Vue实例中的数据绑定到HTML元素的属性上,从而实现数据和视图的实时同步。v-bind指令通常使用简写方式“:”来表示,例如“:class”、“:style”等。下面是v-bind的使用示例
<template> <div :class="{'active': isActive}"></div> <div v-bind:class="{'active': isActive}"></div> </template> 在上述示例中,isActive是Vue实例中定义的数据属性,通过v-bind指令与HTML元素的class、src、href属性进行绑定。当Vue实例中的数据发生改变时,绑定的HTML元素属性也会自动更新。
动态添加类: 在 Vue 中,可以通过绑定 class 的方式动态添加类。
我们可以使用 v-bind 或简写的 : 来绑定 class,然后在需要使用 class 的属性上使用绑定变量。
例如,假设我们有一个 data 中的属性 isActive ,我们希望当这个属性值为 true 时,添加一个名为 active 的类。
<!-- 绑定一个类 --> <div :class="{ active: isActive }"></div> <!-- 绑定多个类 --> <div :class="{ active: isActive, 'text-red': isRed }"></div> 代码演示: 此处我是在App.vue文件下写的,下面这段代码可以直接CV到自己的App.vue文件中去。
结构说明: 我创建了一个div给他设置了一个box1的的类,当我点击之后我i希望加上另外一个类来改变当前的显示效果。
什么是USART?
USART(Universal Synchronous/Asynchronous Receiver Transmitter)是一种通用同步/异步收发器,常用于串行通信。USART可以通过串行线路将数据进行传输,用于与其他设备(如计算机、微控制器、外设)进行通信。
通信相关:
全双工:同时接收和发送
半双工:同一时间只能发送或接收
单 工:要么只能发送要么只能接收
串行:(单车道)
传输原理:数据按位顺序来传输
优点:占用引脚少
缺点:速度低
并行:(8车道)
传输原理:数据各个位同时传输
优点:速度快
缺点:占用多个引脚
USART可以通过两种模式进行通信:同步模式和异步模式。
本章节stm32中以异步模式配置
在异步模式下,数据以帧的形式传输,每个帧包含一个起始位(Start Bit)、数据位(Data Bits)、校验位(Parity Bit)和停止位(Stop Bit)。帧的长度通常为 8 位(1 个起始位、6-8 个数据位、1 个奇偶校验位和 1-2 个停止位),但也可以是其他长度。
串口:
串口一般默认为全双工通信,USART一般也被称为串口
串口必备要素:
信号线:
TXD:发送数据的信号线
RXD:接收数据的信号线
传输参数:
起始位:发送器一般是通过发送起始位来表示一个字符的传输
数据位:要发送的那个字符的每一位数据
停止位:用来表示一个字符的传输结束
校验位:用于检测数据传输是否正确,USART使用的是奇偶校验位,用来检查数据是否有丢失
波特率:每秒传输多少bit位数据,例如115200就是一秒传输115200个bit位
在STM32使用串口,首先添加USART外设,添加相关固件
根据芯片封装原理图找到每块开发板对应的引脚(例如我的stm32F407ZET6主控开发板)
由图可以看出,我这款芯片串口1复用的引脚为PA9(tx)和PA10(rx)
根据原理图可知,串口1 的两条信号线分别为:
PA9:USART_TX,发送信号线,复用输出模式
PA10:USART_RX,接收信号线,复用输入模式
分析串口初始化配置,如图(图片来的更直观一些)
下面是具体的配置步骤,虽然图片已经很清楚了,但是为了还有人不明白,再具体写一下
具体芯片以具体情况来看,我这个是STM32F4系列的库函数,如果有小伙伴学习STM32F1系列的,库函数可能不同,但是配置步骤大同小异
1、使能时钟:USART1、GPIO
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); 2、初始化GPIO,并选择复用功能
//初始化GPIO引脚,以及复用 GPIO_InitTypeDef GPIO_struct_init; GPIO_struct_init.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10; //引脚 GPIO_struct_init.GPIO_Mode = GPIO_Mode_AF; //输出模式:复位 GPIO_struct_init.
Latches and Flip-Flops(触发器和锁存器) Dff——D触发器 D Latch 从做题的角度来说,首先你得认识这个元件。同 D触发器相比,这个元件没有 clk 端口,取而代之的是 ena 端口,所以这是一个锁存器。锁存器的特征在于,相较于 D触发器的触发事件发生于 clk 时钟的边沿,锁存器锁存的触发事件发生于使能端 ena 的电平。
当你成功实现了这个锁存器时,Quartus 会提醒(祝贺)你生成了一个锁存器。锁存器相比触发器会消耗更多的资源,所以综合器会在推断出锁存器时产生提醒,防止开发者在不想使用锁存器时,因为代码风格等原因误产生了锁存器。
always@(*)begin
if(ena)begin
q<=d;
end
end 上图为带有异步复位AR端口的D触发器 asynchronous reset
code:
module top_module (
input clk,
input d, input ar, // asynchronous reset
output q);
always@(posedge clk or posedge ar)begin
if(ar)begin
q <= 1'b0;
end else begin
q <= d;
end
end
endmodule
同步复位
always @(posedge clk)begin
if(r)begin
q <= 0;
end else begin
总览 安装了k8s控制面板,方便日常的问题处理,查看资源状态信息,也可以增加子账号进行开放给其他人员使用,减少命令操作,提升工作效率
前置条件 须有一个正常使用的k8s集群附k8s v1.23版本搭建:https://blog.csdn.net/u010800804/article/details/124524688 Kubesphere【推荐】 面向云原生应用的容器混合云KubeSphere 愿景是打造一个以 Kubernetes 为内核的云原生分布式操作系统,它的架构可以非常方便地使第三方应用与云原生生态组件进行即插即用(plug-and-play)的集成,支持云原生应用在多云与多集群的统一分发和运维管理。 资源信息 KubeSphere 是在 Kubernetes 之上构建的以应用为中心的多租户容器平台,提供全栈的 IT 自动化运维的能力,简化企业的 DevOps 工作流。KubeSphere 提供了运维友好的向导式操作界面,帮助企业快速构建一个强大和功能丰富的容器云平台。中国官方网站:https://www.kubesphere.io/zh/开源地址:https://github.com/kubesphere/kubesphere平台内置的多租户设计,让不同的团队能够在一个平台中不同的企业空间下,更安全地从云端到边缘部署云原生应用。开发者通过界面点击即可快速部署项目,平台内置丰富的云原生可观测性与 DevOps 工具集帮助运维人员定位问题和快速交付。KubeSphere 还能帮助基础设施团队在数据中心与多个云上高效地部署与运维多集群,避免单一云厂商绑定。 KubeSphere 是在 Kubernetes 之上构建的面向云原生应用的分布式操作系统,完全开源,支持多云与多集群管理,提供全栈的 IT 自动化运维能力,简化企业的 DevOps 工作流。它的架构可以非常方便地使第三方应用与云原生生态组件进行即插即用 (plug-and-play) 的集成。
作为全栈的多租户容器平台,KubeSphere 提供了运维友好的向导式操作界面,帮助企业快速构建一个强大和功能丰富的容器云平台。KubeSphere 为用户提供构建企业级 Kubernetes 环境所需的多项功能,例如多云与多集群管理、Kubernetes 资源管理、DevOps、应用生命周期管理、微服务治理(服务网格)、日志查询与收集、服务与网络、多租户管理、监控告警、事件与审计查询、存储管理、访问权限控制、GPU 支持、网络策略、镜像仓库管理以及安全管理等。
KubeSphere 还开源了 KubeKey 帮助企业一键在公有云或数据中心快速搭建 Kubernetes 集群,提供单节点、多节点、集群插件安装,以及集群升级与运维。
在线安装 最小化安装 KubeSphere 准备工作 Kubernetes 版本必须为:v1.20.x、v1.21.x、* v1.22.x、* v1.23.x 和 * v1.24.x。带星号的版本可能出现边缘节点部分功能不可用的情况。因此,如需使用边缘节点,推荐安装 v1.21.x机器满足最低硬件要求:CPU > 1 核,内存 > 2 GB检查集群中是否有默认 StorageClass(准备默认 StorageClass 是安装 KubeSphere 的前提条件)参考地址:https://www.kubesphere.io/zh/docs/v3.3/installing-on-kubernetes/introduction/prerequisites/ 命令安装 在k8s master节点执行命令 kubectl apply -f https://github.
未来可期 人生值得
目录
一、什么是Dapp?
二、Dapp和App有什么区别?
区别总结
三、成为区块链Dapp,必须具备以下条件:
四、Dapp的分类
五、Dapp的优点是什么?
六、Dapp的缺点是什么?
七、Dapp的特点
八、Dapp的目前发展
九、Dapp的未来趋势
一、什么是Dapp? Dapp是Decentralized Application的缩写,翻译过来就是去中心化应用,也称为分布式应用。
Dapp 就像您使用的任何其他软件应用程序一样没有什么区别。它可以是您手机上的网站或应用程序。Dapp 与传统应用程序(APP)的不同之处在于它是建立在分布式(P2P)网络上运行的软件应用程序。它不是托管在集中式服务器上,而是托管在点对点分散式网络上。比如以太坊。
一句非常直白的话来解释Dapp,那就是:把我们目前依靠IOS和Android系统开发的App抓出来,扔在区块链系统上,结合智能合约,它就成了Dapp。
二、Dapp和App有什么区别? Dapp强调分布式
传统App强调中心化;
Dapp强调去中心化;去中心化,不是不要中心,而是由节点来自由选择中心、自由决定中心。必须运行在分布式的操作系统,即区块链系统上。Dapp上的数据归用户所有,而非Dapp的开发者,即个人隐私不会被第三方收集。
虽然Dapp的运行尽管不依靠任何中心服务器,但是离不开智能合约。只有依托智能合约的约束,才能让Dapp无需听命于任何中心化服务器或节点,实现自治。
数据可以进行加密储存
App信息存储在数据服务平台,可以由运营方直接修改;
Dapp数据加密后存储在区块链,难以篡改; Dapp数据加密后存储在区块链上,由区块链负责数据的保存和交换,这样就可以在没有中介的情况下进行产权交易和销售。同时,Dapp必须保证参与者的信息被安全存储,保护个人的数字资产、产权不被破坏、泄露。
有一定的Token奖励机制
App没有奖励机制;
Dapp需要Token用以激励矿工验证及创造区块;矿工需用POW工作证明来换取更多的Token和权益。简单来说,Token是维持一个Dapp发展的重要动力。
区别总结 对比App,两者最大不同就是中心化与去中心化。App先要有钱,所以先融资;然后再有人,所以招齐人后再开发运营。而Dapp则是继承传统App并结合区块链的特点所形成的产物,它更像是众筹模式、共享模式和去中心化模式,Dapp先有发起人或组织,写好白皮书明确了共识机制和token分配与激励,持有token的人即为股东,直接和Dapp的盈利关联(也可以说用户即是股东),持有的token像股票可以买卖,在支持的交易所交易,所以持有该Dapp的token相当于拥有所有者权益。可以想象,未来各个领域都会有Dapp,每个人都将因token分类、以token群分。
三、成为区块链Dapp,必须具备以下条件: 应用程序必须完全开源,自主运行,没有实体控制。应用程序的数据和记录必须完全公开。应用程序必须使用加密货币(不一定是系统本身的代币)。 四、Dapp的分类 根据去中心化的对象,Dapp可以进行分类。对于一个中心化服务器而言,包括计算、存储能力,以及所产生的数据三个方面,而由数据之前的关联度又产生了某种特定的“关系”。因此一般而言,去中心化包括以下几类,
一是基于计算能力的去中心化(如POW机制)二是基于存储能力的去中心化(如IPFS)三是基于数据的去中心化(如STEEMIT)四是基于关系的去中心化(如去中心化ID) 五、Dapp的优点是什么? Dapp在以下几个方面拥有优势:
去中心化:没有单点故障,政府或者个人很难控制整个网络。持续工作:依靠P2P系统,即使个人的电脑或者一部分网络瘫痪,Dapp依然可以运行。区块链基石:通过智能合约可以轻松将加密货币整合到Dapp的基本功能中。源代码公开:促进Dapp生态系统的广泛开发,促使开发者开发出更多有用和有趣的功能。 六、Dapp的缺点是什么? Dapp在以下几个方面也有缺陷:
黑客:因为Dapp的智能合约是开源的,黑客可以分析并找到漏洞。Dapp很容易遭到黑客的攻击,这可能会威胁用户的资金安全。可用性:很多Dapp几乎都没有用户界面,但随着时间推移这方面应该会改善。用户:Dapp的使用用户很少,导致了Dapp交互性很差。抵制审查:Dapp可以自由运行的能力导致了旁氏骗局、逃出骗局和所谓的暗杀市场。 七、Dapp的特点 DApp通过网络节点去中心化操作。可以运行在用户的个人设备之上,比如:手机、个人电脑。永远属于用户,也可以自由转移给任何人。DApp运行在对等网络。不依赖中心服务器,不需要专门的通信服务器传递消息,也不需要中心数据库来记数据。数据保存在用户个人空间,可能是手机,也可能是个人云盘。DApp数据加密后存储在区块链上。可以依托于区块链进行产权交易、销售,承载没有中介的交易方式。DApp参与者信息被安全储存。可以保护数字资产,保证产权不会泄露、被破坏。DApp必须开源、自治。可以由用户自由打包生成,签名标记所属权。它的发布不受任何机构限制。 各种创意与创新可以自由表达和实现。 八、Dapp的目前发展 一个新技术的发展,一般会经历触发期、期望膨胀期、幻想破灭期、复苏期、价值期。
目前,基于区块链技术的Dapp尚处于早期探索状态,还没有大规模实际应用价值的Dapp出现。但不可否认的是区块链技术带给了我们巨大的想象空间,从现在的情形来看打造完全去中心化的app至少还需要几年时间。
虽说Dapp还没有达到绝大多数人手机都有安装的程度,但Dapp的发展已经在路上。
九、Dapp的未来趋势 Dapp的优势在于,它有着区块链特有的数据确权、价值传递等特有功能,Dapp在用户认证流程变更、行业生产关系变更、交易安全、降低技术开发成本、减少运维成本等等方面具有很大的优势,也能在最大程度上提升用户的体验感、参与感。
区块链技术的去中心化特征,给我们带来了巨大的遐想空间,基于区块链技术的Dapp目前还没有大规模实际应用,可以说是处于襁褓中,但却有着巨大的发展空间。我们相信,随着区块链的继续发展,Dapp相关应用会随着技术的发展而得到进一步普及。
本文禁止转载!!!!!
脑机接口科普0022——黑门02:伦理道德问题_sgmcy的博客-CSDN博客
前文中,罗列了一下脑机接口这个技术中,会遇到哪些伦理道德的问题。
前文末,以黑门中救人的一个话题,展示了脑机接口中的其中一个伦理问题。
确切的说,这个救人的伦理问题,从来不是属于脑机接口单独的伦理问题,是所有人工智能产业都会遇到的伦理问题。
救A还是救B? 这个问题或许过于简单,现实中,遇到的问题,要比这个更加复杂,所以,有人就提出了“电车难题”,试图以这个难题,挑战人的道德底线。
有一列火车,如果正常行驶,就会杀掉5个人。
你是那个具有操纵杆权限的人
你如果拉一下操纵杆,那么火车就会杀一个人。
这个问题,就是伦理道德问题,没有正确答案,怎么选,都是错的。怎么选,都会受到伦理道德的“审判”!!!
这个电车难题中涉及的伦理,其实应用在智能驾驶中,是最合适的。
智能驾驶,做决策的是机器,而非人。在上图的情况下,智能系统该下什么命令,去撞死一个人还是去撞死3个人?
所以现在的智能汽车,不得不分为5个等级,什么L0~L4
其实分等级,最主要的原因,就是没解决上面这个撞人的问题。其他都是次要问题。
智能驾驶,我可以设置的速度慢一点,可以使用雷达探测器进行探测,只要有一点点障碍物,我都可以等待,直到障碍物消失。这样系统也可以有足够的时间做出决策,进行刹车,避免速度太快,来不及反应,造成交通事故。
这种情况下,智能驾驶是可以实现的。
但是,还是那句话,“既要。。。。又要。。。。还要。。。。”
如果智能驾驶,真的像我上述一样,速度那么慢(话说京东的快递车就是走固定路线,并长时间等待),那么早就被人吐槽死了。所以做智能驾驶的公司,既要速度很快(跟人开的速度一样快),又要安全,还要达到的性能更优(比如可以在完全陌生的路段开。在完全陌生的路段,人驾驶的时候都会放慢速度观察的)。
就是智能驾驶这种“既要。。。。又要。。。。还要。。。。”的精神,导致智能驾驶不得不面对上述的伦理问题,出车祸,选择撞一个人,还是选择撞一堆人。
话又说回来了,出了车祸,这个法律责任是谁来承担,是个人,还是智能系统,还是智能系统背后的汽车开发商,还是汽车开发商背后的数据处理团队?
没解决上述电车难题中的伦理问题,智能驾驶,永远是处于试验品阶段。永远不能真正落地运行。
在前文脑机接口科普0022——黑门02:伦理道德问题_sgmcy的博客-CSDN博客中也举了《黑门》动漫中人工智能驾驶的例子。
到了2058年,人工智能也只是辅助驾驶,到了特地的阶段,还是需要人来手动操控方向盘来驾驶。
想起了《三体》里面罗辑复苏苏醒后的一段对话。
罗辑沉睡了185年后,苏醒了,有个大屏幕上的美女客服跟罗辑打招呼,说可以帮罗辑办理好各种身份证明,银行卡等等,以帮助他适应这个新的智能社会。
罗辑看着眼前这个美女客服,问:你是真人吗?还是虚拟的人工客服?
美女客服笑着回答:我当然是真人了啊!
逻辑一听,心想,完蛋了,人类发展了几百年,人工智能技术还是被三体的智子给封印了,那些表面的繁华社会,不过仅仅是一些所谓的“人工智能”表层应用,真正的基础科学还是没有完全突破三体人的封锁。
程序员有十层楼需要爬。具体是哪十层楼,网上有类似的文章介绍。其中,文章中介绍了第是一层楼,这个第11层楼,就是上帝。
上帝最伟大的功能是什么?是创造人。
有些人会说,我也可以跟我对象创造人啊,我也是上帝吗?
上帝是基于没有的东西创造了人,你是基于已有的物质创造了人(也就是说,人已经存在了,上帝创造人的时候,人是不存在的),所以你不是上帝。
假如,给你一堆泥土和石头,你可以从这些石头里面,提炼出芯片,并且用这些芯片,做成了一个机器人,并且从这些泥土石头里面,培育出了一些类似人的皮肤的材料,附着上这个机器人上面,并且,你写了代码,让这个机器人足够的智能,跟我们现在的人类一样聪明,并且还有感情,那么,你就成为了上帝。
因为,你创造了一个人工智能,一个不是碳基生命的人,你创造了一个硅基生命的人。
这个硅基生命生命的人,与我们正常人一样,有情感,有思维,有执行力,有决策力,他也受到跟正常碳基生命一样的法律约束,一样的伦理道德约束。
你,就是上帝!就是女娲!
很明显,任何人工智能的发展,都必将面临伦理道德的难题。
不解决这些伦理道德的难题,任何人工智能的发展最后都必将寸步难行。
回过头来,谈谈本文说的电车难题。
如果你是那个决策者,你会选择死一个人,还是选择死5个人?
如果对这个电车难题进行升级呢?如下文所介绍的一样:
设立盲盒、修改轨道……这还是你印象中的“电车难题”吗?
你会怎么选择呢?毕竟,现实中的伦理道德,可比这个假设的情况更加复杂。
链接中的电车难题,假设了各种情况,比如,你要么就选择死5个人,如果你选择死1个人,后面其他人也要受你选择的影响,他们还会继续面临着电车难题。
解决伦理道德难题的方法,或许,法律是一种途径。
正如法外狂徒张三所说,老婆和妈掉水里了,救哪一个?法律规定,救妈。
但是,诚如法外狂徒张三,也说出了如下的例子:
法外狂徒张三还举过这么个例子,说一个20几岁的年轻人,救了一个90几岁的人,好像是消防员救人,也好像是救溺水者。
这个问题怎么理解?
张三说,生命不是简单的数字替换,不是简单的加减。生命的本质还有其他的含义。还有整个社会的核心价值观。
对,这个社会的核心价值观,就是指,伦理道德。
法律,是解决伦理道德问题的方法之一,但法律解决不了所有的伦理道德问题。
最后,谈一个额外的话题。
就是关于法制社会。
西方社会,认为法制社会是最好的。人人都按照法律来。
但是,殊不知的是,法律,造成了这个社会的人情淡薄,造成了钻法律的漏洞。
我们这个国家,历经了五千年,在这五千年的时间内,中国人探索了很多治理国家的方法。
什么王道治天下,霸道治天下,无为而治,法治,人治,孝治,仁治。。。。。。
要明白一个事情,就是对于一个面积超级大的国家,民族超级多的国家而言,法制不是一个唯一的途径,必须是多种混合模式综合起来治理的方式。
单单一个法制,会造成很多社会问题的。
最简单的,如果单纯靠法制,会有多少人犯罪,如果宣传一些积极向上的价值观,以道德伦理来约束众人,不要犯罪,也是极好的。甚至,佛教道教里面,导人向善,也是可取的,去除掉宗教里面的迷信成分,这也是宗教存在的价值。
回到黑门里面救A还是救B的问题,这就是一个伦理道德问题。
这个问题无解,不管怎么做,都会有问题。
如果把两个人都救活了,监管机构会调查主人公的师傅,因为他没有按照指令救人。
如果系统下发指令需要救的人,没有救活,那么这个没有救活的人的家属,会法律控告这个医生或者监管机构。
如果癫痫病人没有救活,那么,癫痫病人的家属,会控告这个医生或者监管机构,见死不救。
总之,里外不是人,怎么都是错。
随着互联网技术的发展和数据的遍及,数据战争已经愈发充分地展开。各种数据的来源、采集和分析方式也不断涌现。其中,通过API接口进行网站数据抓取,已经成为了数据分析和应用开发的必备技能之一。这篇文章将为大家介绍如何使用API接口在Python中抓取网站数据。
API接口是数据共享的标准化方式之一,它可以将网站的数据以规定的格式(JSON或XML)发布出来,供需要访问数据的用户进行访问和数据抓取。Python是一个强大的编程语言,具有良好的数据处理和实现能力,它可以很好地实现通过API接口抓取网站数据的操作。
首先,要进行API接口网站数据抓取,我们需要获取API密钥。通常这需要注册一个帐户来获得API密钥,比如国外常用的是Google的API接口,而国内常用的是百度地图、高德地图等API接口。这里以百度地图为例,步骤如下:
在百度地图开放平台中申请API Key。根据API文档中指定的接口格式,通过Python中的requests库向API接口发送请求。解析API接口返回的JSON或XML格式的响应内容,并对其进行处理和分析。 其中,requests库为Python中常用的HTTP客户端库,可以方便地向服务器发送HTTP请求,并支持HTTPS协议和HTTP代理,可以满足大多数情况下的数据抓取需要。下面以使用requests库中的get()方法向百度地图API接口发送HTTP请求为例:
import requests ak = 'your_api_key' url = 'http://api.map.baidu.com/location/ip?ak=%s&ip=myip' % ak response = requests.get(url) python复制代码
其中,ak为API密钥,url为API接口请求的URL,response为API接口返回的响应对象。接下来,我们可以使用Python中的json库解析响应内容,并对其进行处理和分析:
import json result = json.loads(response.text) if result['status'] == 0: city = result['content']['address_detail']['city'] print('您当前所在城市为:%s' % city) else: print('获取城市信息失败') python复制代码
以上代码中,我们成功地从百度地图API接口中抓取了当前IP地址所在的城市信息,并将其输出到控制台上。
总的来说,Python + API接口的数据抓取是数据分析和应用开发过程中,不可或缺的技能之一。通过学习和掌握API接口的使用,我们可以更加便捷地抓取网站数据,并将其用于数据分析和各类应用开发中。
1、首先是经典的双线程卖票 public class Test extends Thread{ private int num = 1000; @Override public void run() { while (this.num>0){ System.out.println(Thread.currentThread().getName()+"出售了"+this.num+"号票"); num--; } } public static void main(String[] args) { Test test1 = new Test(); Thread thread1 = new Thread(test1, "一窗口"); Thread thread2 = new Thread(test1, "二窗口"); thread1.start(); thread2.start(); } } 当然以上代码也就产生了经典的一票多卖的问题,产生的原因是因为线程在修改一个变量的值时,会从主存将此变量的值拷贝一个副本,每次是先修改的副本,然后再更新主存中的值,由此就造成了其它线程获取主存中值时获取到的不是最新的值,也就造成了卖票重复。
如果有的同学电脑运行速度飞快,不会出现这样问题,可以参照3.1的代码,模拟此问题。
2、synchronized 可以保证同一时刻被synchronized修饰的代码块只被一个线程所访问,即对线程建立了同步锁。如果作用于静态方法,则锁的是这个方法所在的类;作用于其它,则锁的是实例出的对象。
2.1、run方法修改如下 public void run() { while (this.num>0){ synchronized (this){ System.out.println(Thread.currentThread().getName()+"出售了"+this.num+"号票"); num = num -1; } } } 注意,synchronized不要设置在方法上或者循环外边啊,因为设置在循环之外,一窗口获取到同步锁之后,由于循环没有执行完,会一直占据着同步锁,因此票都需要一窗口来卖,可恶,996出现了!