Docker

Docker#

docker img

教程手册#

好用的使用教程

Install#

略过~ 😁

打镜像和跑#

docker build -t server:v0 . -f server.dockerfile

#

docker run -p 9080:80 --name server server:v0

指定启动命令#

sudo docker run -it -p 9080:80 --name nova_server nova_server:v0 sh -c "echo hello"

加入自定义网络#

--network {{network name}} 详见:[[#Network]]

跑出问题-进入容器排查#

sudo docker run -it -p 9080:80 --name nova_server nova_server:v0 sh -c "bash"

使用-it进入容器手动执行命令进行调试

启动全部容器#

docker ps -a | grep "Exited" | awk '{print $1}' | xargs docker start

Network#

  1. docker run时容器加入方法-redis为例
  2. 后期加入方式
  3. 创建一个新网
  4. 检测
    init_redis:
    	docker run -p 6379:6379 \\
    	--network websafe-network \\
    	--name redislatest redis:latest --requirepass 3b21d032a7fd8eb51fa7bd8a2e812b78b7b3a36f 
    
    join_network:
    	docker network connect websafe-network mysql56
    	docker network connect websafe-network daemon-xxx
    
    init_network:
    	docker network create websafe-network
    
    check_network:
    	docker network inspect websafe-network
    	docker network inspect websafe-network | findStr IPv4Address
    

删除#

可视化#

go install github.com/jesseduffield/lazydocker@latest

如果需要sudo权限的话无法直接执行命令,只能where获取原始路径后sudo+原始路径执行 如:

Docker

Docker#

docker img

教程手册#

好用的使用教程

Install#

略过~ 😁

基础命令#

打镜像和跑#

#

docker build -t server:v0 . -f server.dockerfile

dockerignore#

如果您想在 Dockerfile 中将当前目录中的所有文件都复制到 Docker 镜像中,可以使用 Dockerfile 中的 COPY 指令。具体的语法如下:

COPY . /目标路径/

其中. 表示当前目录,/目标路径/ 表示目标路径,这里可以是绝对路径或相对路径。 这将会将当前目录中的所有文件复制到镜像中的 /app/ 目录下。请注意,在这种情况下,所有文件和文件夹都会被复制到镜像中,包括隐藏文件和文件夹。如果您不想复制某些文件或文件夹,可以在运行 COPY 指令之前通过 .dockerignore 文件来指定忽略的文件和文件夹。

#

docker run -p 9080:80 --name server server:v0

指定启动命令#

sudo docker run -it -p 9080:80 --name nova_server nova_server:v0 sh -c "echo hello"

加入自定义网络#

--network {{network name}} 详见:[[#Network]]

跑出问题-进入容器排查#

sudo docker run -it -p 9080:80 --name nova_server nova_server:v0 sh -c "bash"

使用-it进入容器手动执行命令进行调试

Golang进阶笔记

Golang进阶笔记#

golang

性能分析#

import (
    "net/http"
    _ "net/http/pprof"
)

go func() {
    log.Println(http.ListenAndServe("localhost:6060", nil))
}()

将以上代码插入程序中 启动之后执行

go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30

具体使用方法可以help 如果使用top的话就可以查看方法占用了

(pprof) top
Showing nodes accounting for 29.59s, 98.60% of 30.01s total Dropped 35 nodes (cum <= 0.15s)
flat flat% sum% cum cum%
28.98s 96.57% 96.57% 28.98s 96.57% time.Now
0.24s 0.8% 97.37% 0.51s 1.70% runtime.selectgo
0.16s 0.53% 97.90% 0.16s 0.53% memeqbody
0.13s 0.43% 98.33% 0.29s 0.97% runtime.mapaccess2_faststr 
0.08s 0.27% 98.60% 29.95s 99.80% example.com//pts/services/monitor.Run

如以上就是说monitor.Run方法中使用了select, 然后其中的time.Now被疯狂执行.

路径问题#

test_test.go#

package main

import "testing"

func TestHelloWorld(t *testing.T) {
	// t.Fatal("not implemented")
	path := getCurrentPath()
	t.Log("getCurrentPath: ", path)
}

test.go#

package main

import (
	"fmt"
	"log"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"strings"
)

func main() {
	fmt.Println("getTmpDir(当前系统临时目录) = ", getTmpDir())
	fmt.Println("getCurrentAbPathByExecutable(仅支持go build) = ", getCurrentAbPathByExecutable())
	fmt.Println("getCurrentAbPathByCaller(仅支持go run) = ", getCurrentAbPathByCaller())
	fmt.Println("getCurrentAbPath(最终方案-全兼容) = ", getCurrentAbPath())
	fmt.Println("getCurrentPath(runtime.Caller1) = ", getCurrentPath())
}

// 最终方案-全兼容
func getCurrentAbPath() string {
	dir := getCurrentAbPathByExecutable()
	if strings.Contains(dir, getTmpDir()) {
		return getCurrentAbPathByCaller()
	}
	return dir
}

func getCurrentPath() string {
	_, filename, _, _ := runtime.Caller(1)

	return path.Dir(filename)
}

// 获取系统临时目录,兼容go run
func getTmpDir() string {
	dir := os.Getenv("TEMP")
	if dir == "" {
		dir = os.Getenv("TMP")
	}
	res, _ := filepath.EvalSymlinks(dir)
	return res
}

// 获取当前执行文件绝对路径
func getCurrentAbPathByExecutable() string {
	exePath, err := os.Executable()
	if err != nil {
		log.Fatal(err)
	}
	res, _ := filepath.EvalSymlinks(filepath.Dir(exePath))
	return res
}

// 获取当前执行文件绝对路径(go run)
func getCurrentAbPathByCaller() string {
	var abPath string
	_, filename, _, ok := runtime.Caller(0)
	if ok {
		abPath = path.Dir(filename)
	}
	return abPath
}

输出#

ian@ianDebian:~$ ./test
getTmpDir(当前系统临时目录) =  .
getCurrentAbPathByExecutable(仅支持go build) =  /home/ian
getCurrentAbPathByCaller(仅支持go run) =  /home/ian
getCurrentAbPath(最终方案-全兼容) =  /home/ian
getCurrentPath(runtime.Caller1) =  /home/ian
ian@ianDebian:~$
ian@ianDebian:~$ go run test.go
getTmpDir(当前系统临时目录) =  .
getCurrentAbPathByExecutable(仅支持go build) =  /tmp/go-build3048077768/b001/exe
getCurrentAbPathByCaller(仅支持go run) =  /home/ian
getCurrentAbPath(最终方案-全兼容) =  /tmp/go-build3048077768/b001/exe
getCurrentPath(runtime.Caller1) =  /home/ian
ian@ianDebian:~$
ian@ianDebian:~$ go test test_test.go test.go -v
=== RUN   TestHelloWorld
    test_test.go:8: getCurrentPath:  /home/ian
--- PASS: TestHelloWorld (0.00s)
PASS
ok  	command-line-arguments	0.002s

Golang 私有仓库#

xxx替换为具体地址

UE4 笔记

UE4 笔记#

ue4

手机#

  • 路径必须不能用汉字, 一律全英文(神奇…以前习惯就是全英,以为这问题是上世纪的了,测试时不知怎么就把顺手的英文换成中文了,结果就莫名中枪了)
  • java8 (ue4.26.2, 之前4.25也是, 反正就找个稳定版java一直使吧, 这语言太amazing了.)
  • 虽然对java版本有一定要求, 不过按照我这次的测试和使用, 觉得折腾那么久完全是汉字项目名不支持…所以java版本要求应该不是很严重

动画#

事件图表&动画图表#

  • 事件图表: 收集动画->存储在变量中
  • 动画图表: 驱动所有动作

事件图表#

isValid#

蓝图不知道被哪个实例持有(通用)

朝向#

主角本地坐标X轴正方向表正前方

  1. GetVelocity

  2. RotationFromXVector

  3. GetControlRotaion

2,3求Delta.

输出#

  • 速度
  • 方向

总步骤#

  • 向量长度获取Speed
  • 向量方向-控制器方向获取Direction
  • 以上2保存为变量, 交由动画图表

动画图表#

Params-Blend-Result:

  1. 获取速度,方向(看情况可多可少)
  2. 1输入动画混合空间
  3. 输出姿势

State Machine#

在以上一组动作中加入状态细分

  • State Machine - State1-(rule)-State2…StateN
  • State - (Params-Blend-Result)

生效#

  1. 角色
  2. 网格体(骨骼网格体)
  3. 动画-动画类-动画蓝图

愉快的Java(happy to learn the fuck java)

happy to learn the fuck java 😅#

<微人事> 笔记 -> ψ(._. )>#

先贴官方文档 哦 还有官方项目地址

Java语法#

爪哇方法定义:#

修饰符  返回值类型  方法名(参数类型  参数名){
    方法体;
	return 返回值;
}

# 示个例
public boolean NiHou(int num){
	int a = num;
	return turn;
}

// `boolean` 处 可为
public Collection<? extends GrantedAuthority> getAuthorities(){
	List<GrantedAuthority> authorities = new ArrayList<>();
	return authorities;
}
// 表泛型中可以是的`GrantedAuthority`所有子类

爪哇抽象方法(即Python父类中直接pass的函数…)#

abstract

  1. 包含抽象方法必须得是抽象类
  2. 任何子类必须重写父类抽象方法,或者声明自身为抽象类
public abstract class Employee
{
   private String name;
   private int number;
   
   public abstract double computePay();
   
   //其余
}

爪哇接口#

interface, implements

Golang笔记

Golang笔记#

golang 先贴一个客观的教程文档网站http://www.runoob.com/go/go-slice.html

垃圾回收#

常见的回收算法#

  1. 引用计数
    • 优点:对象可以被很快回收
    • 缺点:不太好处理循环引用
  2. 标记-清除
    • 优点:解决了引用计数的缺点
    • 缺点:需要 STW(Stop The World),暂时停止程序运行
  3. 分代收集(按照对象生命周期长短划分不同的代空间,生命周期长的放入老年代,段的放入新生代,不同代有不同的回收算法和回收频率)
    • 优点:回收性能好
    • 缺点:算法复杂
  4. 三色标记法(初始状态:白色、从根节点开始遍历,遍历到的变成灰色,遍历灰色,将灰色引用的标记灰色,遍历过的灰色对象变为黑色。循环遍历灰色对象。通过写屏障检测对象的变化,重复。收集所有白色对象(垃圾))

GPM调度和CSP模型#

CSP 模型?#

CSP 模型是“以通信的方式来共享内存”,不同于传统的多线程通 过共享内存来通信。用于描述两个独立的并发实体通过共享的通 讯 channel (管道)进行通信的并发模型。

GPM 分别是什么、分别有多少数量?#

• G(Goroutine): 即Go协程,每个go关键字都会创建一个协 程。 • M(Machine):工作线程,在Go中称为Machine,数量对应真 实的CPU数(真正干活的对象)。 • P(Processor): 处理器(Go中定义的一个摡念,非CPU), 包含运行Go代码的必要资源,用来调度 G 和 M 之间的关联关 系,其数量可通过 GOMAXPROCS() 来设置,默认为核心数。 M必须拥有P才可以执行G中的代码,P含有一个包含多个G的队 列,P可以调度G交由M执行。

Goroutine调度策略#

• 队列轮转:P 会周期性的将G调度到M中执行,执行一段时间 后,保存上下文,将G放到队列尾部,然后从队列中再取出一个 G进行调度。除此之外,P还会周期性的查看全局队列是否有G等 待调度到M中执行。 • 系统调用:当G0即将进入系统调用时,M0将释放P,进而某个空 闲的M1获取P,继续执行P队列中剩下的G。M1的来源有可能是 M的缓存池,也可能是新建的。 当G0系统调用结束后,如果有空闲的P,则获取一个P,继续执 行G0。如果没有,则将G0放入全局队列,等待被其他的P调度。 然后M0将进入缓存池睡眠。 ![[goroutine.png]]

CHAN 原理#

结构体#

type hchan struct {
	qcount uint // 队列中的总元素个数
	dataqsiz uint // 环形队列大小,即可存放元素的个数
	buf unsafe.Pointer // 环形队列指针
	elemsize uint16 //每个元素的大小
	closed uint32 //标识关闭状态
	elemtype *_type // 元素类型
	sendx uint // 发送索引,元素写入时存放到队列中的位置
	recvx uint // 接收索引,元素从队列的该位置读出
	recvq waitq // 等待读消息的goroutine队列
	sendq waitq // 等待写消息的goroutine队列
	lock mutex //互斥锁,chan不允许并发读写
}

读写流程#

向 channel 写数据:#

  1. 若等待接收队列 recvq 不为空,则缓冲区中无数据或无缓冲区,将直接从 recvq 取出 G ,并把数据写入,最后把该 G 唤醒,结束发送过程。
  2. 若缓冲区中有空余位置,则将数据写入缓冲区,结束发送过程。
  3. 若缓冲区中没有空余位置,则将发送数据写入 G,将当前 G 加入sendq ,进入睡眠,等待被读 goroutine 唤醒。

从 channel 读数据#

  1. 若等待发送队列 sendq 不为空,且没有缓冲区,直接从 sendq中取出 G ,把 G 中数据读出,最后把 G 唤醒,结束读取过程。
  2. 如果等待发送队列 sendq 不为空,说明缓冲区已满,从缓冲区中首部读出数据,把 G 中数据写入缓冲区尾部,把 G 唤醒,结束读取过程。
  3. 如果缓冲区中有数据,则从缓冲区取出数据,结束读取过程。
  4. 将当前 goroutine 加入 recvq ,进入睡眠,等待被写 goroutine唤醒。

关闭 channel#

  1. 关闭 channel 时会将 recvq 中的 G 全部唤醒,本该写入 G 的数据位置为 nil。将 sendq 中的 G 全部唤醒,但是这些 G 会panic。
panic 出现的场景还有:#
  • 关闭值为 nil 的 channel
  • 关闭已经关闭的 channel
  • 向已经关闭的 channel 中写数据

无缓冲 Chan 的发送和接收是否同步?#

// 无缓冲的channel由于没有缓冲发送和接收需要同步
ch := make(chan int)
//有缓冲channel不要求发送和接收操作同步
ch := make(chan int, 2)

channel 无缓冲时,发送阻塞直到数据被接收,接收阻塞直到读 到数据;channel有缓冲时,当缓冲满时发送阻塞,当缓冲空时接 收阻塞。

Vn.Py学习笔记(Python交易平台框架)

author: Ian

Vn.Py笔记 ✏📔#

vn.py#

一个开源Python交易软件,主使用CTP协议。当然,还有其他协议了其源项目在http://www.vnpy.org/




初期笔记#

报单交易过程中,

CTP使用BrokerID 从业务层面完全隔离不同经纪公司的交易、风控及结算用户的接入。
BrokerID具体取值咨询开户的经纪公司。

CTP中 UserID为操作员代码,InversterID为投资者代码; 投资者自己下单两者同为投资者代码

CTP-API中,OrderRef和OrderAction    前者为CTP后台提供给客户端标识一笔报
单的字段,从客户端可通过(FrontID、SessionID、OrderRef)唯一确定一笔报
单;;;后者与OrderRef功能相似,提供给客户端来标识一笔撤单。
前者的数据类型为字符数组,必须为阿拉伯数字字符。
OrderRef(OrderActionRef)取值必须保证在同一会话内发送的报单
OrderRef(OrderActionRef)值大于之前的最大值,开发多线程客户端尤为需要  
注意。

CTP-API库:

error.dtd\error.xml 错误定义文件    ----   ThostFrfcMdApi.h 
交易接口类定义文件  
———   ThostFtfcUserApiDataType.h 类型定义文件  ------    
thostmduserapi.lib,thostmduserpi.dll 行情接口库文件     -----   
thosttraderapi.lib,thosttraderapi.dll交易接口库文件   ----- 

交易和行情接口类定义文件都包含API 和 SPI类定义,客户端使用API向CTP后台
发送请求,CTP后台则使用SPI向客户端回传响应及回报

行情Demo开发:
    1.将API文件复制到工程目录;并将所有的头文件和静态、动态库连链接库
并将文件导入到项目工程中。
    先继承行情接口类CThostFtdcMdspi,并实现需要实现的虚函数。  
OnFrontConnectde、OnFrontDisconnected、OnPspUserLogin、
OnRspSubMarketDAta

/API工作流程***/

API压缩包——API含常量对应字符、类型定义、操作系统编译定义、回调函数(MdSpi)(柜台向用户端发送信息后被系统自动调用的函数)、主动函数(MdApi)(向柜台发送各种请求和指令)

API工作流程: 创建MdSpi对象(回掉函数),调用MdApi类,以Create开头的静态方法,创建MdApi对象(主动函数),注册MdSpi对象指针,行情柜台前置机地址,调用MdApi对象Init方法初始化连接前置机,连接成功会通过OnFrontConnected回调通知用户,用户获得连接成功通知后,调MdApi的ReqUserLogin登陆,登陆后MdSpi的OnRsqUserLogin通知用户 ———————-到此登陆完成———————

MdApi:(行情相关)
    使用MdApi对象的SubscribeMarketData方法,传入参数为想要订阅的“合约
代码”,订阅成功当合约有新行情通过MdApi的OnRtnDepthMarketData回调通知   
用户

———————-至此订阅完成——————— 当用户的某次请求发生错误时,会通过OnRspError通知用户 MdApi也含有退订合约、登出功能。 而一般退出程序则直接杀进程(不太安全便是)

数据库-MongoDB篇

DB数据库 🖥 📊🖥#

db

MongoDB笔记#

学习网站:http://www.runoob.com/mongodb/mongodb-tutorial.html (其学习教程还挺可观,很多,不过还不清楚好不好)

安装#

Docker 安装 4.4.12版本#

pull:
	docker pull mongo:4.4.13
run:
    docker run -itd --name mongo --restart=always \
        -v /mongodb/datadb:/data/db \
        -p 27017:27017 \
        --network websafe-network \
        --privileged=true mongo:4.4.12

进入容器docker exec -it mongo bash后:

mongo
use admin

# db.createUser({user: "admin", pwd: "admin", roles: [{role: "root", db: "admin"}]})
# db.createUser({user: "admin", pwd: "admin", roles: [{role: "userAdminAnyDatabase", db: "admin"}]})
# 如果能auth就不用createUser了
db.auth("admin", "admin")

网上传的将 MONGO_INITDB_ROOT_PASSWORDMONGO_INITDB_ROOT_USERNAME传入环境变量的方式,在mongo4.4.12 和 4.4.13上都不好使。

数据迁移#

insert into device_data_current select * from device_data;

使用 mysqldump#

很慢 很大 很方便 很!不好!使用!在使用–host时 下面命令没一次正常工作的,很难受

数据库-MySQL篇

MySQL数据库 🖥 📊🖥#

db

安装#

docker#

podman run -d --name mysql-container -e MYSQL_ROOT_PASSWORD={my-secret-pw} -e MYSQL_TIME_ZONE=UTC  -e MYSQL_CHARSET=utf8 -p 3306:3306 mysql:5.7

MySQL 客户端#

如果没有mysql-client可以安装 MariaDB 客户端#

sudo apt update
sudo apt install mariadb-client

安装完成后,命令也是 mysql,用法完全相同

使用#

常用命令#

CREATE DATABASE {database_name} DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci;

按天统计#

SELECT 
    DATE(created_at) AS date,
    COUNT(*) AS count
FROM 
    `TABLE_NAME`
WHERE 
    created_at >= "2025-01-01" AND created_at < "2025-02-01"
GROUP BY 
    DATE(created_at)
ORDER BY 
    date LIMIT 100

连接#

使用MySQL命令行工具连接MySQL时,你可以使用以下命令来:

启用压缩传输#

mysql --compress -u username -p

完整命令如:

mysql --compress -u{username} -p{passwd} --host {host}  {db name}

2024-05-27: 但是很可惜,很多第三方连接库都不支持这个参数。