查看RV1126SDK内的sensor驱动,发现可以直接用的型号并不多,在实际项目实现的过程中,还是需要调试新的sensor,因此记录一下调试过程,之后的Sony系列都可以套用这个过程来实现。
首先确保硬件供电正常,另外i2c地址、时钟、上拉电阻等都要检查好,确保硬件没问题
在SDK/kernel/driver/media/i2c/ 下有相机sensor的驱动,都是在Linux框架下的,所以可以随便找一个索尼的驱动,在此基础上改。
在此之前要先修改设备树,设备树里主要定义了sensor的i2c地址,时钟频率,供电,复位的gpio、相机模组名、port节点的链接关系、date-lanes等
这里要按照自己原理图的定义去修改,另外ucam0_out节点链接到了mipi_in_ucam0,又链接到了rkcif->isp,因为对camera流的链接要求各不相同,此处不详细写出
&i2c1 { status = "okay"; clock-frequency = <400000>; imx585: imx585@37 { compatible = "sony,imx585"; reg = <0x37>; clocks = <&cru 103>; clock-names = "xvclk"; power-domains = <&power 9>; pinctrl-names = "rockchip,camera_default"; pinctrl-0 = <&mipicsi_clk0>; avdd-supply = <&vcc3v3_sys>; dovdd-supply = <&vcc_1v8>; dvdd-supply = <&vcc_dvdd>; reset-gpios = <&gpio1 28 1>; rockchip,camera-module-index = <1>; rockchip,camera-module-facing = "front"; rockchip,camera-module-name = "YT10092"; rockchip,camera-module-lens-name = "IR0147-60IRC-8M-F20"; ir-cut = <&cam_ircut0>; port { ucam_out0: endpoint { remote-endpoint = <&mipi_in_ucam0>; data-lanes = <1 2 3 4>; }; }; }; }; 在~/workspace/RV1126SDK/kernel/drivers/media/i2c下编辑Makefile,添加编译输出
1.建立脚本文件asmn vim /usr/local/rebootAutoStart/asmn.sh #!/bin/bash nohup /usr/local/minio/minio server /data3/minio/data > /usr/local/minio/autostart.log 2>&1 & /usr/local/tomcat/tomcat-8.5.60_8080/bin/startup.sh chmod +x /usr/local/rebootAutoStart/asmn.sh 2.建立asmn服务 cd /etc/systemd/system/ vim asmn.service [Unit] Description=RebootAutoRestart After=network.target [Service] Type=forking ExecStart=/usr/local/rebootAutoStart/asmn.sh [Install] WantedBy=multi-user.target # 赋予执行权限 chmod 754 asmn.service systemctl daemon-reload systemctl status asmn.service 3.asmn加入开机自启 systemctl enable asmn.service systemctl is-enabled asmn.service 其他 对于asmn.service文件 [Unit] Description=描述服务 After=描述服务类别 [Service] Type=forking-后台运行 User=root-服务启动用户 Group=root-服务启动用户 ExecStart=服务的启动命令 ExecReload=重启命令 ExecStop=停止命令 PrivateTmp=表示给服务分配独立的临时空间 [Install] WantedBy=multi-user.target-多用户命令行时安装此服务
vue+elementUI竖向表格 <template> <div class="content"> <el-table v-if="true" ref="tableList" :data="rawData" width="98%" border size="mini" > <template v-for="(col) in months"> <el-table-column :key="col.key" align="center" style="background:#909399" header-align="center" :prop="col.key" :label="col.label" :width="col.width" min-width="80px" /> </template> </el-table> </div> </template> <script> import { returnRateReportList } from '@/api/customerReturnRate/customerReturnRate' export default { data() { return { maxHeight: 0, search: { queryMethod: 0, startYearMonth: '2020-01-01', endYearMonth: '2020-12-30' }, month: [], page: { page: 1, limit: 100, total: 0 }, months: [ { key: 'item', label: '月别', width: '240px' }, { key: 'one', label: '2023-01', width: '120px' }, { key: 'two', label: '2023-01', width: '120px' }, { key: 'three', label: '2023-01', width: '120px' }, { key: 'four', label: '2023-01', width: '120px' }, { key: 'five', label: '2023-01', width: '120px' }, { key: 'six', label: '2023-01', width: '120px' }, { key: 'seven', label: '2023-01', width: '120px' }, { key: 'eight', label: '2023-01', width: '120px' }, { key: 'nine', label: '2023-01', width: '120px' }, { key: 'ten', label: '2023-01', width: '120px' }, { key: 'eleven', label: '2023-01', width: '120px' }, { key: 'twelve', label: '2023-01', width: '120px' } ], rawData: [] } }, mounted() { }, created() { this.
方式一:
// dome.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #define _CRT_SECURE_NO_WARNINGS #include <iostream> //#include "tools.h" #include <functional> using namespace std; #include <vector> template <typename T1> void run(T1 &a); template <class T> class A { friend void run<>(A<T> &a); public: T name; A(T name):name(name){} private: int i = 10; }; template <typename T1> void run(T1 &a) { cout << a.i << endl; } int main() { A<string> aa("杨皓"); cout << aa.name << endl; run(aa); return 0; } 这么写就行了,说白了模板函数定义一个类型,传入任何类的引用去定义!
一致性哈希算法(consistent hashing) 对于分布式存储,不同机器上存储不同对象的数据,我们使用哈希函数建立从数据到服务器之间的映射关系。
一、使用简单的哈希函数 m = hash(o) mod n
其中,o为对象名称,n为机器的数量,m为机器编号。 考虑以下例子:
3个机器节点,10个数据 的哈希值分别为1,2,3,4,…,10。使用的哈希函数为:(m=hash(o) mod 3)
机器0 上保存的数据有:3,6,9
机器1 上保存的数据有:1,4,7,10
机器2 上保存的数据有:2,5,8
当增加一台机器后,此时n = 4,各个机器上存储的数据分别为:
机器0 上保存的数据有:4,8 机器1 上保存的数据有:1,5,9 机器2 上保存的数据有:2,6,10 机器3 上保存的数据有:3,7 只有数据1和数据2没有移动,所以当集群中数据量很大时,采用一般的哈希函数,在节点数量动态变化的情况下会造成大量的数据迁移,导致网络通信压力的剧增,严重情况,还可能导致数据库宕机。
二、一致性哈希 一致性hash算法正是为了解决此类问题的方法,它可以保证当机器增加或者减少时,节点之间的数据迁移只限于两个节点之间,不会造成全局的网络问题。
1. 环形Hash空间 按照常用的hash算法来将对应的key哈希到一个具有2^32次方个桶的空间中,即0~(2^32)-1的数字空间中。现在我们可以将这些数字头尾相连,想象成一个闭合的环形。如下图:
2. 将数据通过hash算法映射到环上 将object1、object2、object3、object4四个对象通过特定的Hash函数计算出对应的key值,然后散列到Hash环上。如下图:
Hash(object1) = key1;
Hash(object2) = key2;
Hash(object3) = key3;
Hash(object4) = key4;
3. 将机器通过hash算法映射到环上 假设现在有NODE1,NODE2,NODE3三台机器,通过Hash算法(机器IP或机器的唯一的名称作为输入)得到对应的KEY值,映射到环中,其示意图如下:
Hash(NODE1) = KEY1;
Hash(NODE2) = KEY2;
Hash(NODE3) = KEY3;
4. 将数据存储到机器上 通过上图可以看出对象与机器处于同一哈希空间中,这样按顺时针转动object1存储到了NODE3中,object3,object4存储到了NODE2中,object2存储到了NODE1中。
5. 机器的添加与删除 向集群中添加一台新机器
public class FileReader_ { public static void main(String[] args) { } @Test public void m1() { String filePath = "e:\\hello.txt"; FileReader fileReader = null; try { fileReader = new FileReader(filePath); //循环读取 使用read while (fileReader.read()!=-1){ System.out.print((char) fileReader.read());//默认输出的是int,因此需要转化为char } } catch (IOException e) { e.printStackTrace(); } finally { try { if (fileReader != null) { fileReader.close(); } } catch (IOException e) { e.printStackTrace(); } } } } 以上代码是有可能出现代码输出混乱的情况的,输出效果如下:
可能会出现乱码的问题:
原因可能是文件编码与程序读取时使用的编码不一致。在创建FileReader对象时,没有指定文件的编码格式,因此默认使用的是系统默认的编码格式。如果文件中包含非系统默认编码格式的字符,那么在读取时就会出现乱码。
为了解决这个问题,可以在创建FileReader对象时指定文件的编码格式。例如,如果文件是使用UTF-8编码的,可以这样修改代码:
Boolean 类将基本类型为 boolean 的值包装在一个对象中。一个 Boolean 类的对象只包含一个类型为 boolean 的字段。此外,此类还为 boolean 和 String 的相互转换提供了很多方法,并提供了处理 boolean 时非常有用的其他一些常用方法。
Boolean 类的构造方法 Boolean 类有以下两种构造形式:
Boolean(boolean boolValue);Boolean(String boolString); 其中 boolValue 必须是 true 或 false(不区分大小写),boolString 包含字符串 true(不区分大小写),那么新的 Boolean 对象将包含 true;否则将包含 false。
Boolean 类的常用方法 在 Boolean 类内部包含了一些和 Boolean 操作有关的方法,见表 1。
表 1 Boolean 类中的常用方法 方法返回值功能booleanValue()boolean将 Boolean 对象的值以对应的 boolean 值返回equals(Object obj)boolean判断调用该方法的对象与 obj 是否相等。当且仅当参数不是 null,且与调用该
方法的对象一样都表示同一个 boolean 值的 Boolean 对象时,才返回 trueparseBoolean(String s)boolean将字符串参数解析为 boolean 值toString()string返回表示该 boolean 值的 String 对象valueOf(String s)boolean返回一个用指定的字符串表示的 boolean 值 例 1 编写一个 java 程序,演示如何使用不同的构造方法创建 Boolean 对象,并调用 booleanValue() 主法将创建的对象重新转换为 boolean 数据输出。代码如下:
Python实用教程_spiritx的博客-CSDN博客
python没有switch-case语句,但在Python 3.10 增加了 match-case 的条件判断,不需要再使用一连串的 if-else 来判断了,使用上比switch-case更为强大,match-case是一种结构匹配模式,与switch-case也有许多的差异,所以单列一章进行学习。
简单用法 match subject: case <pattern_1>: <action_1> case <pattern_2>: <action_2> case <pattern_3>: <action_3> case _: <action_wildcard> case _: 类似于 C 和 Java 中的 default:,当其他 case 都无法匹配时,匹配这条,保证永远会匹配成功。
标量 标量是指case后面的匹配值是标量。
标量的用法与C、Java的用法基本相同。
注意,这里的标量只能是常量,以及与常量相当的枚举值,变量是不能作为case后面的匹配值使用的,变量在match-case中有特殊的作用,这一点与其他语言的switch是有很大的差异。
error_code = 500 def http_error(status): match status: case 400: return "Bad request" case 404: return "Not found" case 418: return "I'm a teapot" #case error_code: #这个是错误的,不允许使用任何变量 # return "HTTP-Internal Server Error!" case _: return "
实验预备知识:
1.掌握二叉树的创建和遍历算法。
2.掌握哈夫曼编码原理。
一、实验目的 1.进一步掌握二叉树的存储结构和相应算法。
2.掌握哈夫曼树树的创建和哈夫曼编码。
二、实验环境 ⒈ 硬件:每个学生需配备计算机一台。操作系统:Windows。
⒉ 软件:Windows操作系统+Visual C++。 三、实验要求 1.要求采用二叉链表作为存储结构,完成哈夫曼树的创建。
2.输出对应数据的哈夫曼编码,并求出平均编码长度。
四、实验内容 1.在自己的U盘的“学号+姓名”文件夹中创建“实验5”文件夹,本次实验的所有程序和数据都要求存储到本文件夹中。
2.现在某电报公司假设有10字符进行编码,这10个字符的使用频率如下表所示,请创建哈夫曼树。
A
B
C
D
E
F
G
H
I
J
19
18
16
14
12
8
6
4
2
1
编写函数求出A~J的哈夫曼编码。 #include <iostream> #include <queue> #include <map> using namespace std; struct Node { char data; // 字符 int freq; // 频率 Node* left; Node* right; Node(char d, int f) : data(d), freq(f), left(nullptr), right(nullptr) {} // 这里的Node(char d, int f) : data(d), freq(f), left(nullptr), right(nullptr) {} // 是一个构造函数,用于创建Node对象并进行初始化。 // 它采用了成员初始化列表的方式,将传入的参数d和f分别赋值给data和freq成员变量, // 并将left和right指针初始化为nullptr(空指针)。 //使用成员初始化列表的方式可以提高代码的效率和可读性。 // 在构造函数体中,如果需要对成员变量进行赋值, // 需要使用赋值运算符,这会导致多余的内存分配和拷贝操作。 // 而使用成员初始化列表可以直接对成员变量进行初始化, // 避免了这些额外的操作,从而提高了代码的效率。 //就相当于java的构造函数 }; struct Compare { bool operator()(Node* a, Node* b) { return a->freq > b->freq; } }; //权值越大,在树的前面越小,就是最优的路径解 // 创建哈夫曼树 Node* createHuffmanTree(map<char, int>& freqMap) { priority_queue<Node*, vector<Node*>, Compare> pq;//排序 //这个容器相当于是队列的容器,是其中里面的, //是队列中存放的空间为容器。 //插入数据的步骤,导入数据和排序 for (const auto& pair : freqMap) { Node* node = new Node(pair.
用户修改相关
#查看当前所有的用户 rabbitmqctl list_users #查看guest用户所有拥有的权限 rabbitmqctl list_user_permissions guest #删除原来的guest用户 rabbitmqctl delete_user guest #添加一个新的用户 rabbitmqctl add_user admin 12345678 #给admin设置个角色(tag) rabbitmqctl set_user_tags admin administrator #给admin赋予权限 rabbitmqctl set_permissions -p / admin ".*" ".*" ".*" #查看用户所拥有的权限 rabbitmqctl list_user_permissions admin 队列相关命令
#列出指定vhost的所有队列信息,不带--vhost参数默认是‘/’ rabbitmqctl list_queues --vhost ensbrain_plus #删除指定虚拟主机ensbrain_plus的queue_name队列 rabbitmqctl delete_queue queue_name --vhost ensbrain_plus 服务管理方面的命令
# 设置为开机启动 systemctl enable rabbitmq-server.service # 启动服务 service rabbitmq-server start # 重启服务 service rabbitmq-server restart # 停止服务 service rabbitmq-server stop # 查看当前状态 service rabbitmq-server status 插件相关命令
数组方法 数组原型方法主要有以下这些:
join():用指定的分隔符将数组每一项拼接为字符串
push():向数组的末尾添加新元素pop():删除数组的最后一项unshift():向数组首位添加新元素shift():删除数组的第一项slice():按照条件查找出其中的部分元素splice():对数组进行增删改filter():过滤功能concat():用于连接两个或多个数组indexOf():检测当前值在数组中第一次出现的位置索引lastIndexOf():检测当前值在数组中最后一次出现的位置索引every():判断数组中每一项都是否满足条件some():判断数组中是否存在满足条件的项includes():判断一个数组是否包含一个指定的值sort():对数组的元素进行排序reverse():对数组进行倒序forEach():es5及以下循环遍历数组每一项map():es6循环遍历数组每一项find():返回匹配的项findIndex():返回匹配位置的索引reduce():从数组的第一项开始遍历到最后一项,返回一个最终的值reduceRight():从数组的最后一项开始遍历到第一项,返回一个最终的值toLocaleString()、toString():将数组转换为字符串entries()、keys()、values():遍历数组 …
1. 方法区简介 JVM 的内存模型主要包括程序计数器(Program Counter Register)、虚拟机栈(VM Stack)、本地方法栈(Native Method Stack)、堆(Heap)和方法区(Method Area)。
方法区(Method Area)是所有线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
具体来说,方法区用来存储以下数据:
类的元数据信息:包括类的名称、访问标志、父类、接口、字段、方法等信息。运行时常量池:在Java代码中,常量可以被直接定义在类或接口中,这些常量在编译后被存储在Class文件的常量池中,而运行时常量池则是从Class文件中加载的。静态变量和常量:类的静态变量和常量都存储在方法区中,它们在类加载的时候被初始化并分配内存空间。方法字节码:在Java中,方法的字节码被编译成Class文件并存储在方法区中。即时编译器(JIT)编译后的代码:为了提高程序的执行效率,JIT会将热点代码编译成本地机器码并存储在方法区中。 方法区只是 JVM 规范中定义的一个概念,针对 Hotspot 虚拟机,Java8 之前使用永久代(Permanent Generation,简称 PermGen)实现,而 Java8 之后使用元空间(Metaspace)实现。
JDK8 之前可以通过 -XX:PermSize 和 -XX:MaxPermSize 来设置永久代大小,JDK8 之后,使用元空间替换了永久代,改为通过 -XX:MetaspaceSize 和 -XX:MaxMetaspaceSize 来设置元空间大小。
2. 永久代问题 2.1 内存溢出 永久代的空间是有限制的,可以通过 -XX:PermSize 设置永久代初始容量,通过-XX:MaxPermSize 设置永久代最大容量。
但是当加载过多的类或者常量的时候,就可能导致永久代的空间不足,抛出 java.lang.OutOfMemoryError: PermGen space 异常。尤其是web应用会使用很多框架,这些框架会动态加载很多基础类,更容易导致OOM。
2.2 垃圾回收效率低下 永久代中的类信息一般是在应用程序运行期间不会发生变化的,因此,如果开启了永久代的垃圾回收,就会造成大量的垃圾回收操作,导致垃圾回收效率低下,甚至会引起应用程序的暂停。
此外,由于永久代主要存放 JVM 加载的类信息等永久存在的数据,这使得它在垃圾回收过程中的回收效率相对较低。在某些情况下,频繁触发的 Full GC 不仅无法有效回收永久代空间,还会严重影响 JVM 的性能。
2.3 无法动态调整大小 永久代的大小一旦被设置,就无法动态调整,如果预估错误,就可能导致浪费内存或内存不足的问题。
2.4 无法回收常量池中的内存 在永久代中,常量池是一个非常重要的部分,但是其中的常量无法被回收,即使这些常量已经不再被使用,也无法被垃圾回收器回收,这会浪费内存。
3. 元空间简介 元空间(Metaspace)是 Java8 中引入的一个新概念,用来替代原来的永久代。与永久代不同,元空间并不在虚拟机中,而是存储在本地内存(Native Memory)。
文章目录 1 声明必需赋初值2 声明的变量不能被重新赋值2.1 一般情况2.2 如果变量是一个对象,可以修改对象的属性2.3 如果变量是一个数组,可以修改数组的元素 3 声明的变量一般用大写4 块级作用域5 不允许重复声明 const是ES6中新增的一个关键字,用于声明一个只读的常量,一旦声明后就不能再被修改。有以下几个特点
1 声明必需赋初值 在使用const声明变量时,一定要在声明时就给变量初始化,否则编译会报错'const' declarations must be initialized.。
2 声明的变量不能被重新赋值 2.1 一般情况 一般的,声明的变量不能被重新赋值,否则会报错。Uncaught TypeError: Assignment to constant variable.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>ES6新特性:const关键字</title> </head> <body> <script> const PI = 3.14; PI = 3.1415; //报错 </script> </body> </html> 2.2 如果变量是一个对象,可以修改对象的属性 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="
Clickhouse数据库部署、Python3压测实践 一、Clickhouse数据库部署 版本:yandex/clickhouse-server:latest
部署方式:docker
内容
version: "3" services: clickhouse: image: yandex/clickhouse-server:latest container_name: clickhouse ports: - "8123:8123" - "9000:9000" - "9009:9009" - "9004:9004" volumes: - ./data/config:/var/lib/clickhouse ulimits: nproc: 65535 nofile: soft: 262144 hard: 262144 healthcheck: test: ["CMD", "wget", "--spider", "-q", "localhost:8123/ping"] interval: 30s timeout: 5s retries: 3 deploy: resources: limits: cpus: '4' memory: 4096M reservations: memory: 4096M 建表语句
CREATE TABLE test_table (id int, feild1 String, feild2 String, feild3 String , feild4 String, feild5 String, feild6 String , feild7 String, feild8 String, feild9 String , feild10 String, feild11 String, feild12 String , feild13 String, feild14 String, feild15 String , feild16 String, feild17 String, feild18 String , feild19 String, feild20 String ) ENGINE = MergeTree: 二、Python3插入数据压测 关键库:clickhouse_driver、 concurrent.
//定义字符串 DECLARE v_userids VARCHAR(10000) DEFAULT '111#222#333#444'; //解析后存放在此
DECLARE v_mailarray VARCHAR(10000) DEFAULT ''; IF Length(v_userids) > 0 THEN
A:WHILE i <= Length(v_userids) - Length(REPLACE(v_userids, '#', '')) + 1 do
SET v_temp = substring_index(substring_index(v_userids, '#', i), '#', -1 );
//做一些处理 有个v_mail
IF Length(Trim(v_mail)) > 0 THEN // 有值才赋值
IF Instr(v_mailarray, v_mail) = 0 THEN // 如果此值已经存在,则不存储.相当去重
SET v_mailarray=concat_ws(',', v_mailarray, v_mail);
end IF;
end IF;
SET i=i+1;
end WHILE;
end IF;
多个字段拼接去重是指将多个字段的值按照一定的规则进行拼接,并去除重复的拼接结果。这样可以生成唯一标识符或者进行数据统计。
创建测试表
首先,我们需要创建一个测试表来演示多个字段拼接去重的过程。假设我们有一个users表,包含以下字段:
id name age gender 1 Alice 25 Female 2 Bob 30 Male 3 Alice 25 Female 4 Alice 30 Female 我们将使用这个表来进行演示。
使用GROUP_CONCAT函数进行拼接
MySQL提供了GROUP_CONCAT函数,可以用来将一列的值进行拼接。我们可以使用这个函数来实现多个字段的拼接。
下面的示例将演示如何将name和age字段进行拼接,并去重:
SELECT GROUP_CONCAT(DISTINCT CONCAT(name, age) SEPARATOR ',') FROM users; 运行以上SQL语句,将会返回去重后的拼接结果:
Alice25,Alice30,Bob30 使用CONCAT_WS函数进行拼接
除了GROUP_CONCAT函数,MySQL还提供了CONCAT_WS函数,它可以将多个字段的值进行拼接,并使用指定的分隔符进行分隔。
下面的示例将演示如何将name和age字段进行拼接,并使用逗号作为分隔符:
SELECT CONCAT_WS(',', name, age) FROM users GROUP BY name, age; 运行以上SQL语句,将会返回拼接后的结果:
Alice,25 Alice,30 Bob,30 去除重复的拼接结果
在上述示例中,我们可以看到,使用GROUP_CONCAT或者CONCAT_WS函数可以将多个字段进行拼接,但是它们并不能去除重复的拼接结果。如果我们需要去除重复的拼接结果,可以使用子查询和DISTINCT关键字来实现。
下面的示例演示了如何使用子查询和DISTINCT关键字来去除重复的拼接结果:
SELECT DISTINCT CONCAT_WS(',', name, age) FROM ( SELECT name, age FROM users GROUP BY name, age ) AS subquery; 运行以上SQL语句,将会返回去重后的拼接结果:
PySide6 编写的仪表盘 本代码原链接:https://www.cnblogs.com/wangmantou/p/11662779.html
1、使用了PySide6替换了PyQt5,
2、if i % self._scaleMainNum is 0: 替换成了 if i % self.scaleMainNum == 0:
3、app.exec() 替换成了 app.exec()
效果如下:
#!/usr/bin/env python # -*- coding: utf-8 -*- # Time : 2023/10/26 15:04 # Author : kevin # Software: PyCharm # File : GaugePanel.py # 本代码原链接:https://www.cnblogs.com/wangmantou/p/11662779.html # 差异:如下 # [使用了PySide6替换了PyQt5, # if i % self._scaleMainNum is 0: 替换成了 if i % self._scaleMainNum == 0: # app.exec_() 替换成了 app.exec()] from math import * import sys from PySide6.
前言:哈喽小伙伴们,从这篇文章开始,博主就要带领大家一起进入数据结构与算法的学习啦。
C语言掌握的还不扎实的小伙伴一定要记得先补习哦。
今天我们就先来学习——算法复杂度。
目录
一.算法效率
二.时间复杂度
1.时间复杂度的定义
2.大O的渐进表示法
三.空间复杂度
4.总结 一.算法效率 小伙伴们从开始学习编程到现在,肯定已经做过了不少的编程题,那么我们解决这些题目的思路,就称之为算法。 我们还知道,每一道复杂的题目肯定都不止一种解法,那么我们如何判断一个算法的好坏呢?
算法在编写成可执行程序后,运行时肯定都需要消耗时间和空间。因此,衡量一个算法的好坏,一般是从时间和空间两个维度来衡量的,也就是时间复杂度和空间复杂度。
二.时间复杂度 1.时间复杂度的定义 那么时间复杂度究竟是什么东西呢???
博主这里通俗的告诉大家,实际上就是我们数学上所学习的函数。
那么再简单一点来说,时间复杂度就是我们代码中,某些基本操作的执行次数。 下面我们就通过实际例子来讲解时间复杂度: void Func1(int N) { int count = 0; for (int i = 0; i < N; ++i) { for (int j = 0; j < N; ++j) { ++count; } } for (int k = 0; k < 2 * N; ++k) { ++count; } int M = 10; while (M--) { ++count; } printf("
截取视频生成gif缩略图:
ffmpeg -i test.avi -ss 1 -t 5 -ac 2 -ab 128k -s 90*80 -y -f gif out.gif 截取视频生成jpg缩略图:
ffmpeg -i test.avi -ss 0.5 -vframes 1 -r 1 -ac 2 -ab 128k -s 90x80 -y -f mjpeg out2.jpg -ss:截取视频,开始时间,单位秒;-t:截取时长,单位秒;-vframes:等价于frames:v,输出选项,用于指定输出的视频帧数;-r:帧率,输入和输出均具有该参数,即具体形式为: ffmpeg -r [输入帧率] -i [输入文件路径] -r [输出帧率] [输出文件路径] # 输出视频时长= 图片数量/输入帧率
# 当输入文件为视频时,输入帧率自动识别。
# 当输入文件为图片时,输入帧率默认为25,可指定具体值。
-ac:输出文件中音频的声道数;-ab:输出文件中音频的比特率(常见的音频比特率有 96k, 112k, 128k, 160k, 192k, 256k, 320k);-ar:输出文件中音频的采样率(采样率: 11025Hz、22050Hz、24000Hz、44100Hz、48000Hz);-an:从视频文件中去除音频,即视频静音,如: ffmpeg -i test.mp4 -vcodec copy -an output.
Hadoop和YARN是Apache Hadoop生态系统中的两个重要组件。
Hadoop Jar是用于运行Hadoop任务的命令,它实际上是一个包含所有依赖项和配置文件的Java归档文件(JAR),用于执行Hadoop MapReduce任务。MapReduce是一种分布式计算模型,用于处理大规模数据集的并行计算。
YARN(Yet Another Resource Negotiator)是Hadoop的集群资源管理器。它的作用是管理集群中的计算资源并为应用程序提供资源。YARN允许不同类型的应用程序在同一集群上共享资源。与Hadoop Jar不同,YARN Jar用于运行在YARN上运行的应用程序,而不仅仅局限于MapReduce任务。
因此,Hadoop Jar主要用于运行Hadoop MapReduce任务,而YARN Jar用于运行在YARN上的各种应用程序,包括除了MapReduce之外的其他计算框架,如Spark、Hive等。YARN提供更灵活的资源管理和调度,使得集群可以同时运行多种类型的计算任务,提高了集群的利用率和灵活性。
第一步:package打包Java项目 点击package完成后会出现两个jar包,一般情况使用第一个,第二个为加上依赖的jar包
第二步:上交到集群上(拖拽上传或使用命令) rz -E 命令可以弹出窗口,供选择提交文件
第三步:测试jar包 hadoop jar your.jar com.you.Driver /user/input /user/output yarn jar your.jar com.you.Driver /user/input /user/output 这两条命令运行效果在特定情况下一样,要注意已经启动好相应hadoop服务
your.jar替换为你上传的jar包
com.you.Driver替换为你要运行的类
后面的/user/input为你要测试的文件地址
/user/output为输出测试结果的地址(要保证没有相应的目录)
第四步:进入hdfs上查看是否成功运行 输入hadoop102:9870(未设置主机名与端口号相对应的,则需要将主机名转换为相应端口号才可以进入)网址进入hdfs中查看
一、为什么会出现深浅拷贝 实质上是由于JS对基本类型和引用类型的处理不同。基本类型指的是简单的数据段,而引用类型指的是一个对象,而JS不允许我们直接操作内存中的地址,也就是不能操作对象的内存空间,所以,我们对对象的操作都只是在操作它的引用而已。
二、js中复制初体验 当我们复制一个基本类型的值时,会创建一个新值,并把它保存在新的变量的位置上。而如果我们复制一个引用类型时,同样会把变量中的值复制一份放到新的变量空间里,但此时复制的东西(也就是值)并不是对象本身,而是指向该对象的指针。所以我们复制引用类型后,两个变量其实指向同一个对象,改变其中一个对象,会影响到另外一个。
var num = 10; var num2 = num; var obj = { name: 'Nicholas' } var obj2 = obj; obj.name = 'Lee'; obj2.name; // 'Lee' 解析:var num2 = num; 属于基本类型的复制,直接在栈内存中创建了一块新内存空间给num2,存的值同样是10,num2和num完全无关,而var obj2 = obj因为obj是一个对象,所以属于引用类型的复制,所以此时复制给obj2的只是原先保存在obj变量中的引用地址(指针)而已,此操作过后,obj和obj2两个变量存的都是堆内存那个实际对象的引用地址,两个变量指向了同一个内存空间,所以当obj修改对象的name属性时,其实改的是堆内存中的那个对象,由于obj2和obj指向的是同一个对象,所以打印obj2.name就是修改后的那个name值了
三、js中的深浅拷贝(外加首层浅拷贝) 注意:我们所说的深浅拷贝一般用于引用类型的复制,不用于基本类型复制
浅拷贝: 只复制了引用而未真正复制值
几种浅拷贝的方式:
1、“ = ”运算符
const originArray = [1,2,3,4,5]; const originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}}; const cloneArray = originArray; const cloneObj = originObj; console.log(cloneArray); // [1,2,3,4,5] console.log(originObj); // {a:'a',b:'b',c:Array[3],d:{dd:'dd'}} cloneArray.push(6); cloneObj.a = {aa:'aa'}; console.
环境说明 系统环境 系统:Windows XP IDE: Microsoft Visual C++ 6.0 msado15.dll: 文件版本: 6.2.19041.3570产品版本: 10.0.19041.3570 数据源驱动程序:Oracle in OraClient11g_home1 - Oracle Datebase Client 11g Release 2 (11.2.0.1.0) for Microsoft Windows (32-Bit)
使用的对象 msado15.tlh _ConnectionPtr m_pConnection; HRESULT hr = m_pConnection.CreateInstance(“ADODB.Connection”);
_RecordsetPtr m_pRecordset; m_pRecordset.CreateInstance(“ADODB.Recordset”);
_CommandPtr m_pCommand; m_pCommand.CreateInstance(“ADODB.Command”);
_ParameterPtr pInputParam; pInputParam.CreateInstance(__uuidof(Parameter));
Oracle 存储过程 Procedures
CREATE OR REPLACE PROCEDURE PRO_DISPENSER_DISPENSING ( I_CHFM IN VARCHAR2 , ERR_NO OUT NUMBER , ERR_MSG OUT VARCHAR2 ) AS BEGIN ERR_NO := 1; ERR_MSG := I_CHFM; END PRO_DISPENSER_DISPENSING; 使用Oracle SQL Developer 调用存储过程 DECLARE v_err_no NUMBER; v_err_msg VARCHAR2(100); BEGIN PRO_DISPENSER_DISPENSING('少莫千华', v_err_no, v_err_msg); DBMS_OUTPUT.
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userInfoController': Unsatisfied dependency expressed through field 'userInfoService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userInfoServiceImpl': Unsatisfied dependency expressed through field 'baseMapper'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userInfoMapper' defined in file [D:\idea\java2022SC\yygh_parent\service\service_user\target\classes\com\donglin\yygh\user\mapper\UserInfoMapper.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:639) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE] at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:116) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:397) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1429) ~[spring-beans-5.
快速排序 主要思想:分治
1.确定分界点 (不一定是x)2.调整范围 左侧<=x 右侧>=x3.递归 处理左右两段 #include<iostream> using namespace std; const int N=1e6+10; int n; int p[N]; void quick_sort(int p[], int l,int r){ if(l>=r) return; //即数组中没有数据 直接返回 //也可以写成l==r int x=p[l+r>>1],i=l-1,j=r+1; //执行逻辑是先移动后判断 所以将ij向后移一位 while(i<j){ do i++ ; while(p[i]<x); do j-- ; while(p[j]>x); if(i<j) swap(p[i],p[j]); } quick_sort(p,l,j); //j也可以换成i-1 quick_sort(p,j+1,r); //j也可以换成i //不可以换成quick_sort(p,l,j-1) //j的位置可以保证其右侧的所有元素大于x //且 p[j]<=x的 所以不能将j作为右边界传入(不满足分治的要求) } int main(){ scanf("%d", &n); //用scanf不用cin 是因为scanf更快 for(int i=0;i<n;i++){ scanf("%d", &p[i]); } quick_sort(p,0,n-1); for(int i=0;i<n;i++){ printf("
1. 先将原有官方sources.list文件进行备份
sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak 2. 将原来的sources.list删除掉,然后再创建新的
sudo rm /etc/apt/sources.list # 使用vi时会自动创建文件 sudo vi /etc/apt/sources.list # 也可以先创建后编辑 sudo touch /etc/apt/sources.list 3. 将下列源填写到sources.list文件中(用一个国内源即可)
清华源
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-updates main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-updates main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-backports main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-backports main restricted universe multiverse deb https://mirrors.
😃博主:小猫娃来啦
😃文章核心:轮询与 WebSocket的battle
文章目录 前言轮询的原理及实现WebSocket的原理及实现轮询与WebSocket的比较轮询的应用场景WebSocket的应用场景使用场景的对比与选择WebSocket的安全性考虑WebSocket与服务器端推送技术的比较 前言 在现代Web应用中,实时通信已经成为用户体验的重要组成部分。实时通信指的是通过网站或应用程序实时传输数据并保持连接,在无需手动刷新页面的情况下更新内容。轮询和WebSocket都是用于现实时通信的技术。今天我们来对比一下这两种实现方式,看看到底哪个好。
轮询的原理及实现 什么是轮询
轮询是一种客户端不断向服务器发送请求以获取更新的数据的方式。客户端定期(通常使用定时器)向服务器发送请求,不管服务器是否有新数据。如果服务器没有更新,服务器返回空或者相同的响;如果有新数据,服务器会返回最新的数据。
轮询的工作原理
轮询的工作原理很简单。客户端发起请求,服务器检查是否有新数据。如果有,服务器返回数据;如果没有,服务器等待一段时间,然后返回空响应。客户端接收到响应后,再次发起请求,继续这个过程。
轮询的实现方式
轮询有两种常见的实现方式:定时轮询和递归轮询。定时轮询是设置一个固定的时间隔,每隔一段时间就发送一次请求;递归轮询是在每次请求的回调函数中再次发送请求。
以下是一个使用JavaScript的定时轮询示例:
function pollServer() { fetch('/api/data') .then(response => response.json()) .then(data => { // 处理服务器响应的数据 console.log('Received data:', data); // 继续下一次轮询 setTimeout(pollServer, 5000); }); } // 开始轮询 pollServer(); WebSocket的原理及实现 什么是WebSocket
WebSocket是一种全双工、持久化的通信协议,可以在客户端和服务器之间建立实时的双向通信。与传统的HTTP请求-响应模型不同,WebSocket允许服务器主动向客户端推送数据,而不需要客户端不断发送请求。
WebSocket的工作原理
WebSocket的工作原理基于HTTP协议的升级。客户端向服务器发送一个特殊的Upgrade请求头,服务器收到请求后,如果支持WebSocket协议,将响应101 Switching Protocols,并将连接升级为全双工通信的WebSocket连接。之后,服务器和客户端都可以通过这个连接进行实时的双向通信。
WebSocket的实现方式
在前端,你可以使用WebSocket API与服务器建立WebSocket连接,并通过发送和接收消息来实现实时通信。在服务器端,你需要使用相应的后端框架或库来处理WebSocket连接和消息。
以下是一个使用JavaScript的WebSocket示例:
const socket = new WebSocket('ws://example.com/socket'); socket.onopen = function() { console.log('WebSocket connection established.'); }; socket.onmessage = function(event) { const data = event.
titiFlutter 之 Windows 环境搭建教程(全网最全,亲测有效 2023 年 10月 26 日更新) Flutter SDK 安装 下载地址:
国内加速访问:https://flutter.cn/docs/development/tools/sdk/releases
官网镜像:https://flutter.dev/docs/development/tools/sdk/releases
解压:
将安装包 zip 解压到你想安装 Flutter SDK 的路径,最好不要放到 C 盘,如果不知道放在那个目录,可以跟着本教程放在 D:\java\flutter 目录下:
全局环境变量配置:
找到 此电脑 => 右键 选择 属性 => 点击 高级系统设置 => 会弹出系统属性的窗口,点击 环境变量 按钮 => 找到 path 变量,再双击,之后会弹框出来 => 点击 新建, 然后分别输入flutter解压安装的bin目录和dart-sdk的缓存目录,如不会找,则跟着本教程配置为:
D:\java\flutter\bin 和 D:\java\flutter\bin\cache\dart-sdk
加速镜像地址配置
flutter的包管理,类似于前端的npm,java的maven, 项目中加载包或打包到真机上运行的的时候,需要下载对应的包,由于国内加载国外的镜像很慢,所以需要在 全局环境变量额外中添加配置 加速镜像地址, 如下所示:
PUB_HOSTED_URL=https://pub.flutter-io.cn FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn 配置 PUB_HOSTED_URL 加速地址
配置 FLUTTER_STORAGE_BASE_UR 加速地址
配置gradle加速镜像(2023-10-26 更新 )
flutter项目中,项目的依赖大概分成三种:
相同的数据型态,利用不同的方法分析,就可以解决不同的课题。例如目前已相当纯熟的人脸识别技术,在国防应用可以进行安保工作;企业可做员工门禁系统;可结合性别、年龄辨识让卖场进行市调分析,或结合追踪技术进行人流分析等。
本篇接下来要针对深度学习方法的数据类型或算法,介绍AI常见的应用。
1. 神经网络算法 以算法区分深度学习应用,算法类别可分成三大类:
常用于影像数据进行分析处理的卷积神经网络(简称CNN)文本分析或自然语言处理的递归神经网络(简称RNN)常用于数据生成或非监督式学习应用的生成对抗网络(简称GAN) CNN卷积神经网络(简称CNN) CNN主要应用可分为图像分类(image classification)、目标检测(object detection)及语义分割(semantic segmentation)。下图可一目了然三种不同方法的应用方式。
1、图像分类 (Classification)
顾名思义就是将图像进行类别筛选,通过深度学习方法识别图片属于哪种分类类别,其主要重点在于一张图像只包含一种分类类别,即使该影像内容可能有多个目标,所以单纯图像分类的应用并不普遍。不过由于单一目标识别对深度学习算法来说是正确率最高的,所以实际上很多应用会先通过目标检测方法找到该目标,再缩小撷取影像范围进行图像分类。所以只要是目标检测可应用的范围,通常也会使用图像分类方法。图像分类也是众多用来测试算法基准的方法之一,常使用由ImageNet举办的大规模视觉识别挑战赛(ILSVRC)中提供的公开图像数据进行算法测试。图像分类属于CNN的基础,其相关算法也是最易于理解,故初学者应该都先以图像分类做为跨入深度学习分析的起步。使用图像分类进行识别,通常输入为一张图像,而输出为一个文字类别。
2、目标检测 (Object Detection)
一张图像内可有一或多个目标物,目标物也可以是属于不同类别。算法主要能达到两种目的:找到目标坐标及识别目标类别。简单来说,就是除了需要知道目标是什么,还需要知道它在哪个位置。
目标检测应用非常普遍,包含文章开头提到的人脸识别相关技术结合应用,或是制造业方面的瑕疵检测,甚至医院用于X光、超音波进行特定身体部位的病况检测等。目标识别的基础可想象为在图像分类上增加标示位置的功能,故学习上也不离图像分类的基础。不过目标检测所标示的坐标通常为矩形或方形,仅知道目标所在位置,并无法针对目标的边缘进行描绘,所以常用见的应用通常会以「知道目标位置即可」作为目标。
最常见的算法为YOLO及R-CNN。其中YOLO因算法特性具有较快的识别速度,目前已来到v3版本。R-CNN针对目标位置搜寻及辨识算法和YOLO稍有不同,虽然速度稍较YOLO慢,但正确率稍高于YOLO。使用目标检测进行识别,通常输入为一张图像,而输出为一个或数个文字类别和一组或多组坐标。
3、语义分割 (Semantic Segmentation)
算法会针对一张图像中的每个像素进行识别,也就是说不同于目标检测,语义分割可以正确区别各目标的边界像素,简单来说,语义分割就是像素级别的图像分类,针对每个像素进行分类。当然这类应用的模型就会需要较强大的GPU和花较多时间进行训练。
常见应用类似目标检测,但会使用在对于图像识别有较高精细度,如需要描绘出目标边界的应用。例如制造业上的瑕疵检测,针对不规则形状的大小瑕疵,都可以正确描绘。医学上常用于分辨病理切片上的病变细胞,或是透过MRI、X光或超音波描绘出病变的区块及类别。算法如U-Net或是Mask R-CNN都是常见的实作方法。使用语义分割进行识别,通常输入为一张图像,而输出也为一张等大小的图像,但图像中会以不同色调描绘不同类别的像素。
RNN RNN的特色在于可处理图像或数值数据,并且由于网络本身具有记忆能力,可学习具有前后相关的数据类型。例如进行语言翻译或文本翻译,一个句子中的前后词汇通常会有一定的关系,但CNN网络无法学习到这层关系,而RNN因具有内存,所以性能会比较好。因为可以通过RNN进行文字理解,其他应用如输入一张图像,但是输出为一段关于图像叙述的句子。(如下图)
RNN虽然解决了CNN无法处理的问题,但其本身仍然有些缺点,所以现在很多RNN的变形网络,其中最常被使用的网络之一为长短记忆网络(Long Short-Term Network,简称LSTM)。这类网络的输入数据不限于是图像或文字,解决的问题也不限于翻译或文字理解。数值相关数据也同样可以使用LSTM进行分析,例如工厂机器预测性维修应用,可透过LSTM分析机台震动讯号,预测机器是否故障。在医学方面,LSTM可协助解读数以千计的文献,并找出特定癌症的相关信息,例如肿瘤部位、肿瘤大小、期数,甚至治疗方针或存活率等等,透过文字理解进行解析。也可结合图像识别提供病灶关键词,以协助医生撰写病理报告。
GAN 除了深度学习外,有一种新兴的网络称为强化学习(Reinforcement Learning),其中一种很具有特色的网络为生成式对抗网络(GAN)。
这里不详述GAN的理论或实作方式,而是探讨GAN实际应用的场域。深度学习领域最需要的是数据,但往往不是所有应用都可以收集到大量数据,并且数据也需要人工进行标注,这是非常消耗时间及人力成本。图像数据可以通过旋转、裁切或改变明暗等方式增加数据量,但如果数据还是不够呢?目前有相当多领域透过GAN方法生成非常近似原始数据的数据,例如3D-GAN就是可以生成高质量3D对象。当然,比较有趣的应用例如人脸置换或表情置换。(如下图)
图片来源于网络 另外,SRGAN (Super Resolution GAN)可用于提高原始图像的分辨率,将作为低分辨率影像输入进GAN模型,并生成较高画质的影像(如下图)。这样的技术可整合至专业绘图软件中,协助设计师更有效率完成设计工作。
图片来源于网络 NVIDIA也有提供一些基于GAN的平台的应用,包含透过GauGAN网络,仅需绘制简单的线条,即可完成漂亮的画作,并且还能随意修改场景的风格(如下图)。
2. 基于时间序列的预测算法 时间序列预测就是利用过去一段时间的数据来预测未来一段时间内的信息,包括连续型预测(数值预测,范围估计)与离散型预测(事件预测)等,具有非常高的商业价值。
需要明确一点的是,与回归分析预测模型不同,时间序列模型依赖于数值在时间上的先后顺序,同样大小的值改变顺序后输入模型产生的结果是不同的。
如之前的文章所介绍,时间序列可以分为平稳序列,即存在某种周期,季节性及趋势的方差和均值不随时间而变化的序列,和非平稳序列。
本文为大家总结时间序列预测的有关方法,浅析这些技术并探索如何可以提高这些方法的预测效果。
时间序列预测方法最全总结!
1) 自回归积分移动平均或ARIMA(Autoregressive Integrated Moving Average Model)模型 自回归积分移动平均模型或ARIMA(p,d,q),相当于在自回归移动平均过程(ARMA)的基础上增加了积分要素,相比AR、MA、ARMA模型来说,不再对数据平稳性存在要求,在模型中可以直接通过积分参数d控制数据差异化的次数。
将预测对象按照时间顺序排列起来,构成一个所谓的时间序列,从所构成的一组时间序列的变化规律,推断今后变化的可能性及变化趋势、变化规律,就是时间序列预测法。
时间序列模型其实也是一种回归模型,其基于的原理是,一方面承认事物发展的延续性,运用过去时间序列的数据统计分析就能推测事物的发展趋势;另一方面又充分考虑到偶然因素影响而产生的随机性,为了消除随机波动的影响,利用历史数据,进行统计分析,并对数据进行适合的处理,进行趋势预测。
自回归模型是用自身做回归变量的过程,即利用前期若干时刻的随机变量的线性组合来描述以后某时刻随机变量的线性回归模型,它是时间序列中的一个常见形式。
AR模型利用前期数值与后期数值的相关关系(自相关),建立包含前期数值和后期数值的回归方程,达到预测的目的,因此成为自回归过程。比较自回归过程和MA移动平均过程可知,移动平均过程其实可以作为自回归过程的补充,解决自回归方差中白噪声的求解问题,两者的组合就成为自回归移动平均过程,称为ARMA模型。
从回归方程可知,自回归移动平均模型综合了AR和MA两个模型的优势,在ARMA模型中,自回归过程负责量化当前数据与前期数据之间的关系,移动平均过程负责解决随机变动项的求解问题,因此,该模型更为有效和常用。
介绍时间序列平稳性时提到过,AR/MA/ARMA模型适用于平稳时间序列的分析,当时间序列存在上升或下降趋势时,这些模型的分析效果就大打折扣了,这时差分自回归移动平均模型也就应运而生。ARIMA模型能够用于齐次非平稳时间序列的分析,这里的齐次指的是原本不平稳的时间序列经过d次差分后成为平稳时间序列。
在现实生活中,存在很多非平稳的时间序列,它们的均值和方差是随着时间的变化而变化的,幸运的是,统计学家们发现,很多时间序列本身虽然不平稳,但是经过差分(相邻时间点的指标数值相减)之后,形成的新时间序列就变成平稳时间序列了。因此,差分自回归移动平均模型写成ARIMA(p,d,q)。p代表自回归阶数;d代表差分次数;q代表移动平均阶数。在spss软件中,有时输出的ARIMA模型包括6个参数:ARIMA(p,d,q)(P,D,Q),这是因为如果时间序列中包含季节变动成分的话,需要首先将季节变动分解出来,然后再分别分析移除季节变动后的时间序列和季节变动本身。这里小写的p,d,q描述的是移除季节变动成分后的时间序列;大写的P,D,Q描述的是季节变动成分。两个部分是相乘的关系。因此,ARIMA(p,d,q)(P,D,Q)也被称为复合季节模型。
3. 累积距平法(Cumulative.0ffset. .Verification, COV) /累积偏差法 累积距平是一种用于检验计量器的精度、稳定性和可靠性的方法。该方法通过分别记录被测计量器测量的结果和标准测量结果之间的差值,并将其累积起来,从而计算出平均差值和标准偏差。这种方法的优点在于可以消除系统漂移和运动误差的影响,从而提供更准确的结果。
内容概括:
利用基于对话框的MFC项目实现鼠标点击绘制多边形实现扫描线算法填充多边形 源码见Yushan-Ji/ComputerGraphics: ECNU2023秋 计算机图形学课程实验代码 (github.com)
实验内容 通过鼠标交互输入多边形对各种多边形进行填充,包括边界自交的情况 算法描述 多边形绘制 利用OnLButtonDown和OnRButtonDown函数,实现: 左键点击:开始绘制多边形,并连接上一个顶点和当前点击的顶点右键点击:结束绘制多边形,并连接上一个顶点和第一个顶点
其中,绘制顶点间的连线利用了MoveTo和LineTo函数 另外,为了避免多边形绘制完毕后,程序仍然对鼠标点击事件进行响应,因此需要添加布尔变量IsCompleted,用来监测当前多边形是否绘制完毕
因此在OnLButtonDown和OnRButtonDown函数的最开始,需要添加一个条件判断语句,若IsCompleted为TRUE,则表明多边形已绘制完毕,函数直接返回将所有顶点信息保存在vector<CPoint> points中,便于后续计算边信息 扫描线填充 y++\n清空scanPoints 获取边表 AET更新 获取当前扫描线\n的所有交点 交点排序 填充当前扫描线 首先需要根据points中存储的多边形顶点信息,计算出多边形的边信息,得到ET表 新建Edge类,存储每条边的信息 // 边信息 class Edge { public: float x_lower; // 扫描线与边的交点x值(初始值为线段下端点x值) float dx; // 斜率倒数 float y_upper; // 线段上端点y值 // 构造函数 Edge() : x_lower(0.0), dx(0.0), y_upper(0.0) {} Edge(float x_val, float dx_val, float y_val); }; 新建ET表:map<int, vector<Edge>> ET 建立从线段下端点y值y_lower到多边形所有边vector<Edge>的映射,这样有相同下端点的不同边就能够存储在相同键值的map中,便于后续向AET中添加活性边 获取ET表:通过getET()函数实现 需要判断当前边是否为首尾顶点连成的边计算当前边斜率的倒数dx 若当前边平行于x轴,continue不执行任何操作若当前边平行于y轴,则dx=0不是上述两种情况则正常计算 计算x_lower 和y_upper 初始化、更新AET表 扫描线y初始化为ymin,并将ET表中ymin对应的所有边都添加到AET中对于每一条扫描线,都需要检查AET中是否有非活性边的存在,还要及时添加新的活性边 当y >= y_upper 时,说明该边需要移除当y >= y_lower时,说明该边需要添加到AET中 获取每条扫描线与活性边的交点,存入scanPoints中 对于不同边相交的顶点,不存入对于其他交点,易知交点数量必为偶数,因此成对存入交点 根据scanPoints中交点的x值升序排列所有交点,并进行填充 核心代码 CPolygonFillDlg类中新添加的public成员:
AAC转MP3 - 免费在线将AAC文件转换成MP3
通义听悟-你的工作学习AI助手
#鱼眼模型参考链接
本文假设去畸变后的图像与原图大小一样大。由于去畸变后的图像符合针孔投影模型,因此不同的去畸变焦距得到不同的视场大小,且物体的分辨率也不同。可以见上图,当焦距缩小为一半时,相同大小的图像(横向投影距离一样长),对应的视场角不同。所以为了扩大视野,需要缩小焦距,作为相机坐标系到去畸变图像的投影内参焦距。
理论方面不再多说,直接上代码:
C++ 版本
#include <opencv2/opencv.hpp> #include <string> #include <math.h> using namespace std; //图像去畸变部分/// int main(){ cv::Size img_sizea; std::string image_file = "test.jpeg"; cv::Mat src = cv::imread(image_file); cv::Mat distortiona(img_sizea,CV_8UC3); // 内参 cv::Mat camera_matrixa = (cv::Mat_<double>(3, 3) << 5.4108215568312232e+02, 0.0, 1.0318237337253406e+03, 0, 5.4083086444334469e+02, 1.0225293088570558e+03, 0, 0, 1); cv::Mat distortion_coefficientsa=(cv::Mat_<double >(1,4)<<1.0926628389307196e-01,-6.5713320780575097e-04,8.4866561354316559e-03,-4.2045330300667406e-03); cv::Mat new_intrinsic_mat(3, 3, CV_64FC1, cv::Scalar(0)); camera_matrixa.copyTo(new_intrinsic_mat); //调整输出校正图的视场 new_intrinsic_mat.at<double>(0, 0) *= 0.4; //注意数据类型,非常重要 new_intrinsic_mat.at<double>(1, 1) *= 0.4; //调整输出校正图的中心 new_intrinsic_mat.at<double>(0, 2) *= 1.
文章目录 一、Markdown简介二、Markdown流程图2.1 标准流程图2.2 简易流程图 三、Markdown饼图四、Markdown时序图五、Markdown甘特图附:参考文档 一、Markdown简介 Markdown 是一种轻量级标记语言,创始人为约翰·格鲁伯(John Gruber)。它允许人们使用易读易写的纯文本格式编写文档,然后转换成有效的 XHTML(或者HTML)文档。Markdown支持HTML语法。
二、Markdown流程图 2.1 标准流程图 语法格式:
```mermaid flowchat 语句... ``` 节点语法:
nodeName=>nodeType: nodeText[|flowstate][:>urlLink],其中[]项是可选的。
类型含义nodeName流程图文档中的节点变量名称nodeType节点的类型nodeText被插入到节点中的文本。允许换行flowstate可选的,使用|为节点指定额外的样式urlLink可选的,它使用:>运算符指定要链接到的地址 节点类型nodeType
节点类型表示方法释义开始st=>start: start用作流开始的第一个节点。默认文本是Start结束e=>end: end用作流程结束的最后一个节点。默认文本是End运算操作op=>operation: operation指示流程中需要发生操作输入输出io=>inputoutput: inputoutput指示IO在流程中发生子程序sub=>subroutine: subroutine表示流程中发生了一个子例程判断cond=>condition: condition允许条件或逻辑语句将流程引导到两个路径之一(yesorno)平行线para=>parallel: parallel允许多个流程同时发生 链接urlLink
使用运算符:>将外部链接添加到节点,如下所示:
st=>start: start:>https://www.csdn.net[blank] // 由于[blank]的修饰,该st节点将通过打开新选项卡方式加载https://www.csdn.net地址 e=>end: end:>https://www.csdn.net // 将通过页面导航的方式导航到https://www.csdn.net地址,而不是打开新选项卡 连接语法:
<node variable name>[(<specification1>[, <specification2])]-><node variable name>[[(<specification1>[, <specification2])]-><node variable name>],其中[]项是可选的。连接在节点定义下方各自的部分中定义,通过运算符->指定从一个节点到另一个节点的连接。例如:
nodeVar1->nodeVar2 nodeVar2->nodeVar3 方向direction
定义离开节点的方向,使用<direction>表示,<direction>取值范围为以下四种情况中的一种: leftrighttopbuttom 特定说明符specification
每个节点变量都有可选的说明符,比如方向,在变量名之后使用()包含,,分离,如下所示: nodeVar(spec1, spec2) 示例:
```mermaid flowchat st=>start: 开始:>https://www.csdn.net[blank] e=>end: 结束:>https://www.csdn.net op=>operation: My Operation sub=>subroutine: My Subroutine cond=>condition: linear or polynomial io=>inputoutput: catch something.
文章目录 一、Markdown简介二、Markdown常用语法2.1 文章目录2.1.1 TOC方法2.1.2 手动生成目录 2.2 标题2.3 段落2.3.1 首行缩进2.3.2 字体2.3.2.1 字体加粗2.3.2.2 斜体2.3.2.3 粗斜体2.3.2.4 删除线2.3.2.5 下划线2.3.2.6 字体颜色2.3.2.7 字体大小2.3.2.8 字体高亮 2.3.3 分隔线2.3.4 换行2.3.5 文字居中 2.4 脚注2.5 列表2.5.1 有序列表2.5.2 无序列表2.5.3 列表嵌套 2.6 引用2.7 代码框2.8 链接2.9 图片2.10 表格2.11 锚点2.12 上标与下标2.13 待办事项 附:参考文档 一、Markdown简介 Markdown 是一种轻量级标记语言,创始人为约翰·格鲁伯(John Gruber)。它允许人们使用易读易写的纯文本格式编写文档,然后转换成有效的 XHTML(或者HTML)文档。Markdown支持HTML语法。
二、Markdown常用语法 2.1 文章目录 2.1.1 TOC方法 TOC全称为Table of Content,自动列出全部标题。在文章开头使用[TOC]即可自动生成文章目录。
2.1.2 手动生成目录 将「列表」和「页内超链接」相结合,但有些Markdown编辑器不支持,有点类似于HTML的锚点。
语法格式:
[目录名](#标题链接) 规则:
标题链接格式为: 一个#+被链接标题。标题链接中不能出现大写字母,大写字母用小写字母代替。标题链接中不能出现空格 ,空格 用-代替。目录排布由有序列表或无序列表控制跳转与目录名无关,标题和标题链接符合规则即可 例子(只在VsCode上测试可行):
// 目录 [1 一级标题](#1-一级标题) [1.1 二级标题](#11-二级标题) [1.2 二级标题](#12-二级标题-title) [1.
鼠标在不点击的情况下,直接移动到QT控件上不显示提示信息 当你想用图标作为按钮时,为了让用户知道按钮的功能,这时候就会在QT控件上加上提示信息,在初始化时,使用QT自带的setToolTip方法即可:
setMouseTracking(true); setToolTips("Descriptive information"); 但有时明明已经调用了setToolTips方法,鼠标移动到QT控件上仍然不会有提示信息,这时候就需要具体分析下setToolTips方法是如何实现的,官方说明如下:
This property holds the widget’s tooltip
Note that by default tooltips are only shown for widgets that are children of the active window. You can change this behavior by setting the attribute Qt::WA_AlwaysShowToolTips on the window, not on the widget with the tooltip.
If you want to control a tooltip’s behavior, you can intercept the event() function and catch the QEvent::ToolTip event (e.g., if you want to customize the area for which the tooltip should be shown).
QWebEngine加载网页非常慢,直到提示timeout问题 网上很多博客都说是系统默认设置了自动寻找代理,而使用代理后延迟会变得非常大,关闭系统代理设定即可。
QNetworkProxyFactory::setUseSystemConfiguration(false);
尝试了该方法,但仍然加载网页很慢,并未解决。只好继续分析了。
分析过程: 1. 因为同一个地址,Google浏览器加载很快,而QWebEngine加载就很慢,于是想着用抓包工具wireshark具体抓包分析一下。
2. 两者抓包数据对比一下,发现Google去加载网页时,验证证书这一步与QWebEngine完全不一样,QWebEngine会去验证OCSP,Google则不会,时间都花在验证OCSP这一步了。
3. 想到了出问题的地址用的是GlobalSign的商业证书,目前商业证书走的都是OCSP签名,怀疑是不是因为证书是OCSP签名导致的。
4. 于是找了一个测试地址,重新部署了一个自签名的证书,Windows系统上一测试发现加载还是很慢,不过时间已经从之前的30s缩短至15s了,只好继续抓包定位。
5. 再次抓包发现访问网址的时候总是会去访问ctdl.windowsupdate.com网址,该网址访问超时了。
6. 查找了下Windows官方文档,说是不太可能在网络环境以外信任私有 CA,所以会跑到ctdl.windowsupdate.com验证证书的有效性,最后通过启用关闭自动根证书更新策略,不去访问该网站,果然加载很快,大概2~4s时间。
解决方法: 方法一: 更换证书,使用自签名证书,并且不带CRL地址或者证书签名方式不走OCSP签名,同时启用关闭自动根证书更新策略附: https://learn.microsoft.com/zh-cn/windows-hardware/drivers/install/trusted-root-certification-authorities-certificate-store
方法二: 修改QT源码,找到证书校验位置,跳过证书的校验,在QWebEngine加载网页之前,先使用自定义证书校验方法校验证书,具体源码修改位置如下:
找到QWebEngine源码中的ssl_client_socket_impl.cc文件,修改VerfiyCert()函数如下代码片段:
if (ssl_config_.IsAllowedBadCert(server_cert_.get(), &cert_status) { // 使该判断条件恒为true即可 server_cert_verfiy_result_.Reset(); server_cert_verfiy_result_.cert_status = cert_status; server_cert_verfiy_result_.verified_cert = server_cert_; cert_verification_result_ = OK; return HandleVerifyResult(); }
I²C总线通信协议 (1)I²C概述 I²C(Inter-Intergrated Circuit)集成电路总线,该总线是由飞利浦公司在1980年代初设计出来的。主要是用来连接整体电路,是一种多向控制总线,也就是说多个器件可以连接到同一总线结构下,同时每个器件都可以作为实施数据传输的控制源。
I²C属于半双工同步串行通信方式。
(2)I²C硬件拓扑结构 I²C总线一般有两根线,一个是双向传输的数据线(SDA),另一个是时钟线(SCL),所有接到I²C总线设备上的串行数据线SDA都接到总线的数据线SDA上,各设备的时钟线SCL都接到总线的时钟线SCL上。硬件连接如下图1所示,数据线SDA与时钟线SCL都通过一个上拉电阻连接到电源,初始电平都为高电平,处于空闲状态。每个连接到I²C总线的元器件都有唯一的地址。
图1 I²C硬件连接图 (3)I²C协议 I²C总线在数据传输过程中时钟线SCL始终由主机控制,数据传输期间共有三种信号产生:开始信号,停止信号和应答信号。简单概况如下:
①数据有效性
在时钟线SCL高电平期间内,数据线SDA上的数据必须保持稳定,数据线SDA的数据仅允许在时钟线SCL为低电平时改变,如下图2所示。
图2 数据有效性 ②开始信号
当时钟线SCL处于高电平期间,数据线SDA产生由高电平向低电平的跳变,如下图3所示。
③停止信号
当时钟线SCL处于高电平期间,数据线SDA产生由低电平向高电平的跳变,如下图3所示。
图3 开始信号与停止信号的定义 ④应答信号
总线上的接收器每收到一个字节(8bit)就产生一个应答信号ACK。接收器拉低数据线SDA表示应答,并在应答脉冲期间保持稳定的低电平。若主器件作为接收器时,必须发送数据传输结束的信号给发送器,即它在接收最后一个字节数据的应答脉冲期间不会产生应答信号(NACK,不拉低数据线SDA),如下图4所示。
图4 I²C总线应答信号 ⑤数据帧格式
I²C总线传输的数据信号是广义的,既包括地址信号,又包括真正的数据信号。在开始进行数据传输时,主机发出开始信号后,先传输一个器件地址(共7位,前4位是固定,后3位由硬件决定,即同一设备上可接8个同一器件)以及一位读/写位("0"表示主机发送数据W,"1"表示主机接收数据R),再传输一个字节地址(8位,用来选择从器件内部的第几个字节读/写),最后传输数据。每次数据传输总是由主机发出停止信号而结束。
1)主机向从机发送数据(以E²PROM为例)
1、主机发送起始信号;
2、主机发送从器件地址以及读/写位("0"),主机释放总线,等待从器件应答;
3、主机发送需写入的内部寄存器地址,等待从器件应答;
4.、主机发送数据
5、主机发送停止信号
6、E²PROM收到停止信号之后,内部进入写周期,大概需要5ms,此期间之内任何操作都不会被E²PROM响应(因此以这种方式的多次写入,需要插入一个延时,否则会导致失败);
注:阴影部分由主机向从机传送,无阴影部分表示从机向主机传送。A表示应答信号(低电平),Ā表示非应答信号(高电平);START表示起始信号,STOP表示停止信号。
2)主机向从机读取数据(以E²PROM为例)
1、主机发送起始信号;
2、主机发送从器件地址以及读/写位("0"),主机释放总线,等待从器件应答;
3、主机发送需写入的内部寄存器地址,等待从器件应答;
4、主机再次发送起始信号,即Restart;
5、主机发送从器件地址以及读/写位("1"),主机释放总线,等待从器件应答;
6、主机读取数据。主机在接收到最后一个字节数据后,不会发出应答ACK信号,于是从器件释放数据线SDA,以允许主机发送停止信号;
7、主机发送停止信号
双开QWebEngine程序,后一次程序加载网页很慢,提示Unable to create cache 分析过程: 1. 第一次与第二次加载相同网页相比,第一次网页加载只花了1s左右,但第二次加载网页时,进度80%~100%期间内,明显卡顿了10多秒,如下图。
2. 根据提示Unable to create cache,有时候也会有Failed to delete the database: Database IO error提示,怀疑是因为使用了同一个缓存路径导致的。
3. 对两次打开程序,分别设置不同的缓存路径,再次测试,发现后一次程序加载网页的速度和第一次基本一致,但仍然会稍微慢点,如下图。
解决方法: 通过函数QWebEngineProfile::setCachePath,QWebEngineProfile::setPersistentStoragePath设置不同的缓存路径和QWebEngine数据。例如:
QWebEngineProfile *profile = QWebEngineProfile::defaultProfile(); if (XXX) { profile->setCachePath("xxx/cache1"); profile->setPersistentStoragePath("xxx/cache1/QtWebEngine"); } else { profile->setCachePath("xxx/cache2"); profile->setPersistentStoragePath("xxx/cache2/QtWebEngine"); }
飞机大战 前言编译环境代码后续 前言 本文基于C语言,使用简单的语法,编写了飞机大战的小游戏,能够用户控制飞机来击落敌机群获取得分,随着得分提高敌机的移动的速度也会提高,玩家得分提高也会升级飞机的子弹的范围,从而提高命中率。
编译环境 visual studio
代码 #include<stdio.h> #include<stdlib.h> #include<conio.h> #include<Windows.h> // 光标移到(X, Y)位置 void gotoxy(int x, int y) { HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); COORD pos; pos.X = x; pos.Y = y; SetConsoleCursorPosition(handle, pos); } //隐藏光标 void HideCursor() { CONSOLE_CURSOR_INFO cursor_info = { 1,0 }; //第二个值为0,表示隐藏光标 SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info); } //全局变量 #define High 25 #define Width 50 //游戏画面尺寸 #define EnemyNum 5 //敌机数量 int position_x, position_y; //飞机的位置 坐标 int canvas[High][Width] = { 0 }; //画布数组 int enemy_x[EnemyNum], enemy_y[EnemyNum]; //敌机的位置 int score; int BulletWidth; //子弹宽度 int EnemyMoveSpeed; //敌机的移动速度 //数据的初始化 void startup() { position_x = High - 1; position_y = Width / 2; canvas[position_x][position_y] = 1; int k; for (k = 0; k < EnemyNum; k++) { enemy_x[k] = rand() % 2; enemy_y[k] = rand() % Width; canvas[enemy_x[k]][enemy_y[k]] = 3; } score = 0; BulletWidth = 0; EnemyMoveSpeed = 20; } //显示画面 void show() { gotoxy(0, 0); int i, j; for (i = 0; i < High; i++) { for (j = 0; j < Width; j++) { if (canvas[i][j] == 0) printf("
二维变换 概念 应用于对象几何描述并改变其位置、方向或者大小的变换叫做几何变换,有时候也被叫做建模变换。而本文仅讨论平面中的几何变换,即二维变换。
矩阵表示和齐次坐标 对于普通的2x2矩阵,我们总是要将平移项与其它变换对应的矩阵写成不同规格,为了统一形式且方便运算,我们需要将2x2的矩阵扩展到3x3。此时,二为坐标必须用三元向量来表示。标准实现技术是将二维坐标 ( x , y ) (x,y) (x,y)扩充到三维 ( x h , y h , h ) (x_h,y_h,h) (xh,yh,h),这称为齐次坐标,这个过程就被叫做齐次化。
对于每一个维度有
x = x h h , y = y h h x = \frac{x_h}{h},y=\frac{y_h}{h} x=hxh,y=hyh
其中非零值 h h h被称为齐次参数。
显然对于齐次参数,可以有无数个非零值,同样也意味着有无数个等价的齐次表达式。既然如此,为了方便计算,不妨令 h = 1 h=1 h=1。
平移变换 对于平移变换,我们可有参数方程
{ x ′ = x + δ x y ′ = y + δ y \begin{cases} x^{'}=x+\delta x \\ y^{'} = y+\delta y \end{cases} {x′=x+δxy′=y+δy
文章目录 1.最终效果2.操作步骤2.1 前置操作2.2 按照自己需求修改内容2.2.1 基本修改2.2.2 额外添加知乎等社交网站链接 2.3 首页修改2.4 查看发布状态2.5 奇怪的错误(头像显示错误)2.6 本地调试2.7 后续修改 3. 项目设置为私密(要付费升级账号才行❌)3.1 取消/解绑fork的依赖关系3.2 设置私密 1.最终效果 2.操作步骤 2.1 前置操作 Fork repo, https://github.com/academicpages/academicpages.github.io进入fork的项目中,点击Setting,把名字改成你的github名字.github.io (yourname.github.io), 下载fork后的项目到本地,vscode打开准备开始编辑修改 2.2 按照自己需求修改内容 2.2.1 基本修改 把_config.yml中的内容全部复制到_config.dev.yml中,后者当做备份,然后对前者进行修改。
主要就是name,baseurl和description个人描述等的修改,这里就不赘述了
参考:
Building an Academic Websitehttps://academicpages.github.io/markdown/https://github.com/linfangjian01/linfangjian01.github.iohttps://bryanyzhu.github.io/ 2.2.2 额外添加知乎等社交网站链接 比如,要添加知乎和csdn的链接
在_config.yml中,author字段里,和上面一样,写上名称和对应的url链接地址在_includes/author-profile.html中,照着下面的复制,然后修改,其中关于class字段的值,可以去网站https://fontawesome.com/search搜索
建议看这个:https://www.w3schools.com/icons/icons_reference.asp,似乎这个网页只支持部分font awesome(font awesome 5)然后填入对应的值即可,例如:
参考:
Way to add blogger icon and link easily? #784https://fontawesome.com/search,可以在这个网站找想要的icon的类名称 2.3 首页修改 左侧的①,其实就是_config.yml文件的Site Author部分,其中关于个人头像,默认给的展位图是720720的png图像,因此自己的图像也尽量是720720的,可以在PPT里裁剪一下,然后用微信发送压缩一下上面的②,其实体现在_data/navigation.yml中,不想要的可以删除或者注释掉,对应的其实是各个子文件夹,例如:Publications对应的就是_publications文件夹,里面可以存放以md文件或者是html文件形成的内容上面的③,对应_pages/about.md文件,可以直接用markdown的一级标题二级标题的井号语法。 2.4 查看发布状态 根据https://docs.github.com/zh/pages/quickstart可知,一般5~10分钟就发布好了,但是实际上,查看Actions就可以看到对应的构建和发布状态,基本上都是1分钟左右
2.5 奇怪的错误(头像显示错误) 头像无法显示,链接多了一个空格
搜索定位问题到文件_includes/author-profile.html
导致这个空格出现的原因是,在添加知乎和csdn的链接后,在VScode中进行了保存,保存时默认对html文件进行了格式化,自动添加了这个空格。
根据如何解决vscode中保存后html自动格式化的问题可知,直接去首选项修改格式即可。
2.6 本地调试 这部分内容我没有试过,来自:https://jayrobwilliams.
Stream
一般来说,cuda c并行性表现在下面两个层面上:
Kernel levelGrid level 到目前为止,我们讨论的一直是kernel level的,也就是一个kernel或者一个task由许多thread并行的执行在GPU上。Stream的概念是相对于后者来说的,Grid level是指多个kernel在一个device上同时执行。
Stream和event简介 Cuda stream是指一堆异步的cuda操作,他们按照host代码调用的顺序执行在device上。Stream维护了这些操作的顺序,并在所有预处理完成后允许这些操作进入工作队列,同时也可以对这些操作进行一些查询操作。这些操作包括host到device的数据传输,launch kernel以及其他的host发起由device执行的动作。这些操作的执行总是异步的,cuda runtime会决定这些操作合适的执行时机。我们则可以使用相应的cuda api来保证所取得结果是在所有操作完成后获得的。同一个stream里的操作有严格的执行顺序,不同的stream则没有此限制。
由于不同stream的操作是异步执行的,就可以利用相互之间的协调来充分发挥资源的利用率。典型的cuda编程模式我们已经熟知了:
将输入数据从host转移到device在device上执行kernel将结果从device上转移回host 在许多情况下,花费在执行kernel上的时间要比传输数据多得多,所以很容易想到将cpu和gpu之间传输数据时间隐藏在其他kernel执行过程中,我们可以将数据传输和kernel执行放在不同的stream中来实现此功能。Stream可以用来实现pipeline和双buffer(front-back)渲染。
Cuda API可分为同步和异步两类,同步函数会阻塞host端的线程执行,异步函数会立刻将控制权返还给host从而继续执行之后的动作。异步函数和stream是grid level并行的两个基石。
从软件角度来看,不同stream中的不同操作可以并行执行,但是硬件角度却不一定如此。这依赖于PCIe链接或者每个SM可获得的资源,不同的stream仍然需要等待别的stream来完成执行。下面会简单介绍在不同CC版本下,stream在device上的行为。
Cuda Streams 所有的cuda操作(包括kernel执行和数据传输)都显式或隐式的运行在stream中,stream也就两种类型,分别是:
隐式声明stream(NULL stream)显示声明stream(non-NULL stream) 默认情况下是NULL stream,在之前未涉及到stream的博文中,都是该类型。如果显式的声明一个stream就是non-NULL stream了。
异步且基于stream的kernel执行和数据传输能够实现以下几种类型的并行:
Host运算操作和device运算操作并行Host运算操作和host到device的数据传输并行Host到device的数据传输和device运算操作并行Device内的运算并行 下面代码是之前常见的使用形式,默认使用NULL stream:
cudaMemcpy(..., cudaMemcpyHostToDevice); kernel<<<grid, block>>>(...); cudaMemcpy(..., cudaMemcpyDeviceToHost); 从device角度看,所有者三个操作都是使用的默认stream,并且按照代码从上到下的顺序依次执行,device本身是不知道其他的host操作怎样执行的。从host角度来看,数据传输都是同步的并且会一直等待,直到操作完成。不过不同于数据传输,Kernel的launch是异步的,host差不多立刻就能重新得到控制权,不用管kernel是否执行完毕,从而进行下一步动作。很明显,这种异步行为有助于重叠device和host之间的运算时间。
上文内容在之前博文都有涉及,这里特别说明的是数据传输,它也是可以异步执行的,这就用到了本次讲的stream,我们必须显示的声明一个stream来分派它的执行。下面版本是异步版本的cudaMemcpy:
cudaError_t cudaMemcpyAsync(void* dst, const void* src, size_t count,cudaMemcpyKind kind, cudaStream_t stream = 0); 注意新增加的最后一个参数。这样,在host issue了这个函数给device执行后,控制权可以立刻返还给host。上面代码使用了默认stream,如果要声明一个新的stream则使用下面的API定义一个:
cudaError_t cudaStreamCreate(cudaStream_t* pStream); 这样就定义了一个可以使用在cuda异步API函数中stream。使用该函数的一个比较常见的错误,或者说容易引起混乱的地方是,这个函数返回的error code可能是上一次调用异步函数产生的。也就是说,函数返回error并不是调用该函数产生error的必要条件。
当执行一次异步数据传输时,我们必须使用pinned(或者non-pageable)memory。Pinned memory的分配如下,具体请参见前面博文:
cudaError_t cudaMallocHost(void **ptr, size_t size); cudaError_t cudaHostAlloc(void **pHost, size_t size, unsigned int flags); 通过在将该内存pin到host的虚拟内存上,就可以将该memory的物理位置强制分配到CPU内存中以便使之在整个程序生命周期中保持不变。否则的话,操作系统可能会在任意时刻改变该host端的虚拟内存对应的物理地址。假设异步数据传输函数没有使用pinned host memory的话,操作系统就可能将数据从一块物理空间移动到另一块物理空间(因为是异步的,CPU在执行其他的动作就可能影响这块数据),而此时cuda runtime正在执行数据的传输,这会导致不确定的行为。
快速选择 找出数组排序后第k个数
主要思想:分治(代码跟快排很像)
#include<iostream> using namespace std; const int N =1e6+10; int p[N]; int n,k; int quick_sort(int l,int r,int k){ if(l==r) return p[l]; //只有一个数据的数组 返回左右都可以 int x=p[l],i=l-1,j=r+1; while(i<j){ do i++; while(p[i]<x); //while(p[++i]<x);也可以 do j--; while(p[j]>x); //while(p[--j]>x);//也可以 if(i<j) swap(p[i],p[j]); } int sl=j-l+1; //求出左边<=x的元素个数 与k比较 if(k<=sl) return quick_sort(l,j,k); //如果k<sl 那么p[k]一定在左边 只用递归对左边排序即可 return quick_sort(j+1,r,k-sl); //如果k>sl 在右边 传入k时注意减去sl } int main(){ cin>>n>>k; for(int i=0;i<n;i++){ cin>>p[i]; } cout<<quick_sort(0,n-1,k)<<endl; }
ServiceAccount为Pod钟的进程提供身份信息。当用户访问集群时(例如使用kubectl命令的时候),apiserver会将用户认证为一个特定的User Account(目前通常是admin,除非系统管理员自定义了集群配置)。Pod容器中的进程也可以与apiserver联系,当他们在连接apiserver的时候,他们会被认证为一个特定的service account(例如default)。
User account是为人设计的,service account是为Pod中的进程调用Kubernetes API而设计的。
User account是跨namespace的,而service account则是仅局限于它所在的namespace。
每个namespace都会自动创建一个default service account
Token controller检测service account的创建,并为他们创建secret
开启ServiceAccount Admission Controller后
每个Pod在创建后都会自动设置spec.serviceAccount为default(除非指定了其他ServiceAccount)
验证Pod引用的service account已经存在,否则拒绝创建
如果Pod没有指定ImagePullSecretes,则把service account的ImagePullSecretes加到Pod中
什么是ImagePullSecretes?
是k8s中用于拉去私有容器镜像的机制。当你在集群中部署使用私有容器镜像的Pod时,通常需要提供身份验证凭据以获取访问权限。
ImagePullSecrets 是一个或多个凭据的集合,用于访问私有的 Docker 镜像仓库。这些凭据通常是通过 Kubernetes 中的 Secret 对象来存储,并在 Pod 配置中引用。Pod 使用这些凭据来获取镜像仓库中的镜像,以确保能够成功拉取私有镜像。
以下是一个示例,展示了如何在 Pod 配置中使用 ImagePullSecrets:
yamlCopy codeapiVersion: v1 kind: Pod metadata: name: my-app spec: containers: - name: my-container image: private-registry.com/my-image:latest imagePullSecrets: - name: my-secret 在上面的示例中,imagePullSecrets 部分指定了一个名为 my-secret 的 Secret,这个 Secret 包含了访问私有镜像仓库所需的凭据。这样,Pod 就可以使用这个凭据来拉取 private-registry.com/my-image:latest 镜像。
转载于C++多线程详解(全网最全) - 知乎,仅用于学习 1、多线程 传统的C++(C++11标准之前)中并没有引入线程这个概念,在C++11出来之前,如果我们想要在C++中实现多线程,需要借助操作系统平台提供的API,比如Linux的<pthread.h>,或者windows下的<windows.h> 。
C++11提供了语言层面上的多线程,包含在头文件<thread>中。它解决了跨平台的问题,提供了管理线程、保护共享数据、线程间同步操作、原子操作等类。C++11 新标准中引入了5个头文件来支持多线程编程,如下图所示:
1.1、多进程与多线程 多进程并发 使用多进程并发是将一个应用程序划分为多个独立的进程(每个进程只有一个线程),这些独立的进程间可以互相通信,共同完成任务。由于操作系统对进程提供了大量的保护机制,以避免一个进程修改了另一个进程的数据,使用多进程比使用多线程更容易写出相对安全的代码。但是这也造就了多进程并发的两个缺点:
在进程间的通信,无论是使用信号、套接字,还是文件、管道等方式,其使用要么比较复杂,要么就是速度较慢或者两者兼而有之。运行多个线程的开销很大,操作系统要分配很多的资源来对这些进程进行管理。 当多个进程并发完成同一个任务时,不可避免的是:操作同一个数据和进程间的相互通信,上述的两个缺点也就决定了多进程的并发并不是一个好的选择。所以就引入了多线程的并发。
多线程并发 多线程并发指的是在同一个进程中执行多个线程。
优点:有操作系统相关知识的应该知道,线程是轻量级的进程,每个线程可以独立的运行不同的指令序列,但是线程不独立的拥有资源,依赖于创建它的进程而存在。也就是说,同一进程中的多个线程共享相同的地址空间,可以访问进程中的大部分数据,指针和引用可以在线程间进行传递。这样,同一进程内的多个线程能够很方便的进行数据共享以及通信,也就比进程更适用于并发操作。
缺点:由于缺少操作系统提供的保护机制,在多线程共享数据及通信时,就需要程序员做更多的工作以保证对共享数据段的操作是以预想的操作顺序进行的,并且要极力的避免死锁(deadlock)。
相关视频推荐
多进程、多线程、线程使用场景分析
高并发场景下,三种锁方案:互斥锁,自旋锁,原子操作的优缺点
手把手实现线程池(120行),实现异步操作,解决项目性能问题
c/c++ linux服务器开发/后台架构师免费学习地址ke.qq.com/course/417774?flowToken=1013300
需要C/C++ Linux服务器架构师学习资料加qun812855908获取(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享
1.2、多线程理解 单CPU内核的多个线程。 一个时间片运行一个线程的代码,并不是真正意义的并行计算。
多个cpu或者多个内核 可以做到真正的并行计算。
1.3、创建线程 创建线程很简单,只需要把函数添加到线程当中即可。
形式1: std::thread myThread ( thread_fun); //函数形式为void thread_fun() myThread.join(); //同一个函数可以代码复用,创建多个线程 形式2: std::thread myThread ( thread_fun(100)); myThread.join(); //函数形式为void thread_fun(int x) //同一个函数可以代码复用,创建多个线程 形式3: std::thread (thread_fun,1).detach(); //直接创建线程,没有名字 //函数形式为void thread_fun(int x) std::thread (thread_fun,1).detach();
For Example 使用g++编译下列代码的方式:
g++ http://test.cc -o test -l pthread #include <iostream> #include <thread> using namespace std; void thread_1() { cout<<"
方法channel.basicAck的作用 在RabbitMQ中,channel.basicAck方法用于确认已经接收并处理了消息。
方法的参数说明 public void basicAck(long deliveryTag,boolean multiple)
参数:
long deliveryTag 消息的唯一标识。每条消息都有自己的ID号,用于标识该消息在channel中的顺序。当消费者接收到消息后,需要调用channel.basicAck方法并传递deliveryTag来确认消息的处理。boolean multiple 是否批量确认消息,当传false时,只确认当前 deliveryTag对应的消息;当传true时,会确认当前及之前所有未确认的消息。 温馨提示:
通过设置multiple参数,可以实现批量确认消息的功能。如果消费者处理消息的速度很快,可以将其设置为true,一次性确认多条消息,提高处理效率。但如果消费者处理消息的速度比较慢,可能会导致消息堆积,造成内存占用过高。因此,在实际使用中需要根据实际情况来确定是否需要批量确认消息。
构建命令
$ gn gen out/ios --args='target_os="ios" target_cpu="arm64" rtc_include_tests=false' --ide=xcode 报错,这个错误是因为存在多个签名的问题,通过错误信息知道其中有一个是无效的(被吊销),移除之后重新执行构建命令就好了。
打开 Keychain Access 应用程序在左侧的导航栏中选择 “login”(登录)在右上角的搜索框中输入证书的标识符或名称,例如 - “501352425@qq.com”右键单击要删除的证书,并选择 “删除” ERROR at //build/config/ios/ios_sdk.gni:142:33: Script returned non-zero exit code. ios_code_signing_identity = exec_script("find_signing_identity.py", ^---------- Current dir: /Users/stone/webrtc/src/out/ios/ Command: python3 /Users/stone/webrtc/src/build/config/ios/find_signing_identity.py --matching-pattern Apple Development: 501352425@qq.com (M4SLWMVGS5) Returned 1 and printed out: Automatic code signing identity selection was enabled but could not find exactly one codesigning identity matching "Apple Development: 501352425@qq.com (M4SLWMVGS5)". Check that the keychain is accessible and that there is exactly one valid codesigning identity matching the pattern.
解决请求https://geo.datav.aliyun.com/areas_v3/bound/geojson?code=630100_full 返回403的问题
<meta name="referrer" content="no-referrer" />
一、Flink概述 Apache Flink 是一个框架和分布式处理引擎,用于对无界和有界数据流进行有状态计算。
1.Flink的特点 我们处理数据的目标是:低延迟、高吞吐、结果的准确性和良好的容错性。
Flink主要特点:
(1)高吞吐和低延迟:每秒处理数百万个事件,毫秒级延迟。
(2)结果的准确性:Flink提供了事件时间和处理时间语义。对于乱序事件流事件时间,事件时间 语义依然能提供一致且准确的结果。
(3)精准一次的状态一致性保证。
(4)可以连接到最常用的外部系统,如Kafka、Hive、JDBC、HDFS、Redis等。
(5)高可用: 本身高可用的设置,加上与K8s,YARN 和 Mesos 的紧密集成,再加上从故障中快速恢复和动态扩展任务的能力,Flink能做到以及少的停机时间7*24全天运行。
2.Flink 对比 SparkStreaming 3.Flink的应用场景 4.Flink的分成API
自定义导航栏 修改 pages.json 在 pages.json 中将 navigateionStyle 设为 custom
新建 systemInfo.js systemInfo.js 用来获取当前设备的机型系统信息,放在 common 目录下
/** * 此 js 文件管理关于当前设备的机型系统信息 */ const systemInfo = function() { /****************** 所有平台共有的系统信息 ********************/ // 设备系统信息 let systemInfomations = uni.getSystemInfoSync() // 机型适配比例系数 let scaleFactor = 750 / systemInfomations.windowWidth // 当前机型-屏幕高度 let windowHeight = systemInfomations.windowHeight * scaleFactor //rpx // 当前机型-屏幕宽度 let windowWidth = systemInfomations.windowWidth * scaleFactor //rpx // 状态栏高度 let statusBarHeight = (systemInfomations.statusBarHeight) * scaleFactor //rpx // 导航栏高度 注意:此导航栏高度只针对微信小程序有效 其他平台如自定义导航栏请使用:状态栏高度+自定义文本高度 let navHeight = 0 //rpx /****************** 微信小程序头部胶囊信息 ********************/ // #ifdef MP-WEIXIN const menuButtonInfo = wx.
java中按行来读取文件内容,一般对文件也是又要求的,比如文件编码utf-8,内容是按行可读,而不是一堆字节码。这类文件,我们按行读取,主要是方便快速查看内容,并且用这些内容来作别的用途,这类文件内容不宜过多,否则加载容易出现意想不到的问题,比如内存不足。
java中按行读取,我们最先想到的就是使用BufferedReader这个IO流。构造这个IO流,我们需要传入一个Reader,而Reader还需要一个文件输入流FileInputStream对象。
如下所示,通过一层一层构建,我们最终通过File构建了一个BufferedReader并且按行读取了文件内容。
public class BufferedReaderExample { public static void main(String[] args) { try (BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream("conf/test.txt")))) { String line; while ((line = in.readLine())!=null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } } } 如下所示,文件读取打印结果截图:
因为这里是按行读取,也就是每一行是一个字符串结果,最终文件内容就是一个多行字符串,有了这个思路,其实可以把这个按行读取的方法抽取为一个工具方法,返回的结果是一个List<String>,这个可以理解,就是字符串集合。这个方法在commons-io三方库里就有提供,如下所示:
package com.xxx.io; import org.apache.commons.io.IOUtils; import java.io.FileInputStream; import java.io.IOException; import java.util.List; public class ReadLineExample { public static void main(String[] args) { try { List<String> list = IOUtils.readLines(new FileInputStream("conf/test.txt"), "