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进入容器手动执行命令进行调试

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. 动画-动画类-动画蓝图

Tips of debuggers

Clang && lldb#

听说clang+lldb >= gcc + gdb, 所以一试:

lldb基本命令#

与GDB相同

  • break (b) - 设置断点,也就是程序暂停的地方
  • run (r) - 启动目标程序,如果遇到断点则暂停
  • step (s) - 进入下一条指令中的函数内部
  • backtrace (bt) - 显示当前的有效函数
  • frame (f) - 默认显示当前栈的内容,可以通过 frame arg 进入特定的 frame(用作输出本地变量)
  • next (n) - 运行当前箭头指向行
  • continue (c) - 继续运行程序直到遇到断点。
clang hello.c -g -o hello
lldb hello
# lldb
b main
run
n
p str

还有颜色 😂 可视效果确实提高了不少 而且这四个工具可以混用,也蛮好.

GDB#

gdb

First and foremost, you will need to compile your program with the flag “-g” (for debug) to run it via GDB. From there the syntax to start debugging is:

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有缓冲时,当缓冲满时发送阻塞,当缓冲空时接 收阻塞。

tip Of vim

Vim 使用#

vim 除去“简便生活”里的几条配置,在纠结是否添加到别的地方,果然还是单独给vim一个使用手册比较好……

注释#

    # 注释
    112s/^/#/g   
    ---
    # 取消注释
    112s/^#//g     

其实 是vim中的 :s替换命令… 下方解释

或者,使用列编辑的模式:

v、选择区域、ctrl q置行首、I插入#、Esc应用到全列
ctrl v、I、#、Esc
因为有的ctrl q或者ctrl v 不能用……

取消,即使用上述方法选中行首,删除第一个字节即可了

替换#

:s/oldWords/newWords/g

g : 代表当前光标所在行。

由此可知:#

^表行首标识符。 /^/表示行首的空字符。 而取消注释中的/^#/即表示行首的#,被//空字符所替换。

删除:g/出现计算意外/d#

:g/出现计算意外/d

查找高亮#

    set hlsearch
    set nohlsearch  

分屏#

实现#

  • 在外部使用-o or -O参数
  • 内部split or vsplit

操作#

  • 移动光标 Ctrl + w hjkl
  • 移动分区Ctrl + w HJKL
  • 统一高度Ctrl + w =
  • 改变高度Ctrl + w +-

more and less#

阅读器~~~ 因为经常读大文件发现了这两个的无敌好处——快。

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也含有退订合约、登出功能。 而一般退出程序则直接杀进程(不太安全便是)

Python 笔记

python

pip cache 目录#

echo $PIP_CACHE_DIR

特殊函数调用 property#

使用字段的方式调用函数

from datetime import datetime
from pydantic import BaseModel
class InstallCountInfo(BaseModel):
	count: int
	total: int
	@property
	def done_rate(self):
		return round(self.count / self.total, 4)
class InstallCount(BaseModel):
	pass_day: int
	install_day: datetime
	info: InstallCountInfo

彻底摆脱to_dictfrom_dict#

使用 pydantic#

BaseModel类型支持:

  • b = BattleAxiePositionInfo.parse_obj(DICT_DATA)
  • b.json()
  • b.dict()
  • parse_file
  • parse_raw
from pydantic import BaseModel
class PositionInfo(BaseModel):
    error: int = -1 # 收集错误
    none: int = 0 # 还没开始
    clicked: int = 1 # 在client 赋此值
    done: int = 2 # 在server 赋此值
    xy: List[int] = [0, 0]
    status: int = 0 # clicked or done or none or error
class BattleAxiePositionInfo(BaseModel):
    our: List[PositionInfo] = [PositionInfo(), PositionInfo(), PositionInfo(), PositionInfo(), PositionInfo(), PositionInfo()]
    enemy: List[PositionInfo] = [PositionInfo(), PositionInfo(), PositionInfo(), PositionInfo(), PositionInfo(), PositionInfo()]

pp = BattleAxiePositionInfo()
print(f"pp json: {pp.json()}")
dict_pp = pp.dict()
pp = BattleAxiePositionInfo.parse_obj(dict_pp)

pp json: {“our”: [{“error”: -1, “none”: 0, “clicked”: 1, “done”: 2, “xy”: [0, 0], “status”: 0}, {“error”: -1, “none”: 0, “clicked”: 1, “done”: 2, “xy”: [0, 0], “status”: 0}, {“error”: -1, “none”: 0, “clicked”: 1, “done”: 2, “xy”: [0, 0], “status”: 0}, {“error”: -1, “none”: 0, “clicked”: 1, “done”: 2, “xy”: [0, 0], “status”: 0}, {“error”: -1, “none”: 0, “clicked”: 1, “done”: 2, “xy”: [0, 0], “status”: 0}, {“error”: -1, “none”: 0, “clicked”: 1, “done”: 2, “xy”: [0, 0], “status”: 0}], “enemy”: [{“error”: -1, “none”: 0, “clicked”: 1, “done”: 2, “xy”: [0, 0], “status”: 0}, {“error”: -1, “none”: 0, “clicked”: 1, “done”: 2, “xy”: [0, 0], “status”: 0}, {“error”: -1, “none”: 0, “clicked”: 1, “done”: 2, “xy”: [0, 0], “status”: 0}, {“error”: -1, “none”: 0, “clicked”: 1, “done”: 2, “xy”: [0, 0], “status”: 0}, {“error”: -1, “none”: 0, “clicked”: 1, “done”: 2, “xy”: [0, 0], “status”: 0}, {“error”: -1, “none”: 0, “clicked”: 1, “done”: 2, “xy”: [0, 0], “status”: 0}]}

Linux 笔记

git fetch –all git reset –hard origin/master git pull linux

交换分区#

大小推荐#

物理内存交换分区(SWAP)
<= 4G至少4G
4~16G至少8G
16G~64G至少16G
64G~256G至少32G

调节操作#

# 查看命令相关
sudo swapo
swapoff swapon
# 关闭现有的交换分区
sudo swapoff /swapfile
# 查看效果
htop
# 预支出一块儿空地
sudo fallocate -l 16G /swapfile
du -sh /swapfile
# 设置权限 防止误操作
sudo chmod 600 /swapfile
# 整上
sudo mkswap /swapfile
mkswap: /swapfile:警告,将擦除旧的 swap 签名。
正在设置交换空间版本 1,大小 = 16 GiB (17179865088 个字节)
无标签, UUID=6de8b5e1-bdc3-4e7b-98c9-6801126fcb0b
# 开!
sudo swapon /swapfile
# 查看
swapon --show
NAME TYPE SIZE USED PRIO
/swapfile file 16G 535.3M -2
# 写到fstab自动挂载
sudo vim /etc/fstab

fstab示例: