go-sdl2 flappy bird编译
发布于
game

逛gocn发现 好玩的github项目 用go做个flappy bird

https://github.com/neomede/flappy.git

弄成go module项目

go mod init ddatsh.com/flappy
go: creating new go.mod: module ddatsh.com/flappy
go: to add module requirements and sums:
        go mod tidy

发现用新版依赖时编译报错

go mod tidy
go: finding module for package github.com/veandco/go-sdl2/sdl_ttf
go: finding module for package github.com/veandco/go-sdl2/sdl_image
ddatsh.com/flappy imports
        github.com/veandco/go-sdl2/sdl_image: module github.com/veandco/go-sdl2@latest found (v0.4.29), but does not contain package github.com/veandco/go-sdl2/sdl_image
ddatsh.com/flappy imports
        github.com/veandco/go-sdl2/sdl_ttf: module github.com/veandco/go-sdl2@latest found (v0.4.29), but does not contain package github.com/veandco/go-sdl2/sdl_ttf

发现和游戏代码提交时间对应的 go-sdl2的 0.1 tag 里的才是 sdl_image、sdl_ttf,新版就省了sdl_前缀

继续修复几行小变化

.\main.go:56:13: undefined: sdl.KeyUpEvent
.\main.go:72:13: undefined: sdl.KeyUpEvent
.\text.go:38:23: font.RenderUTF8_Solid undefined (type *ttf.Font has no field or method RenderUTF8_Solid)

wire
发布于
go

模拟 web 项目初始化过程

package main  
  
import "fmt"  
  
type DB struct {  
}  
  
type Cache struct {  
}  
  
type UserRepo struct {  
   DB    *DB  
   Cache *Cache  
}  
  
type UserService struct {  
   UserRepo *UserRepo  
}  
  
type App struct {  
   UserService *UserService  
}  
  
func (app *App) Start() {  
   fmt.Println("server starting")  
}  
  
func NewDB() (*DB, func(), error) {  
   db := &DB{}  
   cleanup := func() {  
      fmt.Println("close db connection")  
   }  
   return db, cleanup, nil  
}  
  
func NewCache() *Cache {  
   return &Cache{}  
}  
  
func NewUserRepo(db *DB, cache *Cache) *UserRepo {  
   return &UserRepo{DB: db, Cache: cache}  
}  
  
func NewUserService(userRepo *UserRepo) *UserService {  
   return &UserService{UserRepo: userRepo}  
}  
  
func NewApp(userService *UserService) *App {  
   return &App{UserService: userService}  
}  

不使用 wire

手动 new 方式初始化

func main() {  
   db, cleanup, err := NewDB()  
   if err != nil {  
      panic(err)  
   }  
   defer cleanup()  
   cache := NewCache()  
   userRepo := NewUserRepo(db, cache)  
   userService := NewUserService(userRepo)  
   app := NewApp(userService)  
   app.Start()  
}

使用 DI

go install github.com/google/wire/cmd/wire@latest

创建 wire.go  用于生成代码,申明了最初始的入参和最终的产出物

//go:build wireinject  
// +build wireinject  
  
package main  
  
import (  
   "github.com/google/wire"  
)  
  
// InitializeApplication  
func InitializeApplication() (*App, func(), error) {  
   panic(wire.Build(NewDB, NewCache, NewUserRepo, NewUserService, NewApp))  
}
wire .

生成对应的依赖关系和初始化过程

在使用的地方调用对应的初始化方法获得产物即可,不需要关心其中的依赖关系

func main() {  
   app, cleanup, err := InitializeApplication()  
   if err != nil {  
      panic(err)  
   }  
   defer cleanup()  
   app.Start()  
}

wire 在每个 new 方法中支持三个参数,对象,cleanup,error,参数 cleanup 就会在关闭的时候按照依赖的倒序依次进行关闭。

wire 做的事情就是根据你 new 方法的入参和出参,识别了他们之间的依赖关系,生成了对应的初始化代码

rust Non-UTF-8 output
发布于
dev rust

Non-UTF-8 output

D:\dev\vs\Common7\Tools\VsDevCmd.bat
rstc 编译
error: linking with `link.exe` failed: exit code: 1112
  |
  = note: Non-UTF-8 output: msvcrt.lib(chkstk.obj) : fatal error LNK1112: xxx\r\n

error: aborting due to previous error

解决

用 D:\dev\vs\VC\Auxiliary\Build\vcvars64.bat 启动

微信版本历史
发布于
wechat

国内移动社交产品迭代的方向、中国移动社交的进化图谱

rabbitmq
发布于
mq

基本概念

Publisher 发的消息通过 Connection 中的 Channel 到达 Broker 某个 Virtual Host

消息经过指定的 Exchange,根据 Binding 依据,分发到 0~n 个 Queue 中

Queue 中消息等待 Consumer 消费


Message:由消息头和消息体组成。消息头由一系列的可选属性组成,routing-key(路由键)、priority(相对于其他消息的优先权)、delivery-mode(消息持久性)等

Broker:MQ server

Connection: 客户端和Broker间的TCP连接

Channel:要为每个Connection创建Channel,通过 Channel才能执行AMQP命令,一个Connection可包含多个Channels

Exchange:接收生产者发送的消息,并根据Binding规则将消息路由给队列

Queue:存未被消费者消费的消息

Binding:联系Exchange与Queue,Binding后生成路由表

Exchange收到Message解析Header得到Routing Key,根据Routing Key与Exchange Type将Message路由到Queue

  • Binding Key

    由Consumer在绑定Exchange与Queue时指定

  • Routing Key

    由Producer发送Message时指定,两者的匹配方式由Exchange Type决定

Virtual Host:类似于权限控制组,一个virtual host里面可以 若干个Exchange和Queue,权限控制的最小力度

os 内存布局 & malloc
发布于
os

堆/栈

  • 栈: 函数调用基础(维护函数调用的上下文),大多数编程语言存储局部变量函数参数的地方,线程私有

    自动分配,如函数局部变量 int b;自动在栈中为b开辟空间

  • 堆:应用程序动态分配的内存区域,malloc/new,通常是程序的运行库管理栈空间分配

    自行申请,并指明大小,如 p1 = (char *)malloc(10);或c++ new 运算符。注意p1本身在栈中

栈或堆现有大小不够用时,按增长方向扩大自身尺寸,直到预留的空间被用完为止

栈扩展,触发由 expand_stack() 在Linux中处理的页面错误,调用acct_stack_growth()检查是否适合扩展堆栈

栈大小低于RLIMIT_STACK(通常8MB),栈增长,如果已经达到最大栈大小,溢出,段错误(Segmentation Fault)

运行库向操作系统 批发 较大的堆空间,然后 零售 给程序用

全部“售完”或程序有大量的内存需求时,再根据实际需求向操作系统 进货

springcloud
发布于
java spring springcloud

你对Spring Cloud多了解源自于你对Spring Boot有多了解
你对Spring Boot多了解源自于你对Spring Framework有多了解

Spring Cloud是什么

一系列框架的有序集合,基于 Spring Boot,主要还是在 JVM 范畴内来解决微服务架构的挑战

利用Spring Boot的开发便利性简化分布式系统基础设施的开发,如:

服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署

将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来

通过Spring Boot风格进行再封装屏蔽掉复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包

总结来说,Spring Cloud 的思路就是,已经有的我拿来用,实在没有的我再补充

相对于 Dubbo 来说,是整合了整套解决方案的框架,而 Dubbo 只是其中的一个点

版本对应关系

Release Train 发布时间 Spring Boot版本 SC Commons版本 维护信息 主要版本
2020.0.x 2020-12 2.4.x 3.0.0 按计划支持到2023-12
Hoxton 2019-07 2.2.x, 2.3.x (从SR5起) 2.2.x Finchley系列次要版本,常规维护到2021-6
2020-07特殊维护期(不加新功能,只改紧急bug)
2021-12只发布重大错误/安全补丁
Greenwich 2018-11 2.1.x 2.1.x 2020-01停止维护
2020-12-31终结特殊维护期
Finchley 2017-10 2.0.x 2.0.x 2018发布
Edgware 2017-08 1.5.x 1.3.x
Dalston 2017-05 1.5.x 1.2.x
Brixton 2016-09 1.3.x 1.1.x
Angel 2016-05 1.2.x 1.0.x
软中断
发布于
kernel

软中断

点完外卖后,平台虽会显示配送进度,但也不会傻盯着,得去干别的事情,等外卖到了配送员会通过「电话」通知,电话响了,就停下手中地事情,去拿外卖

中断是一种 异步事件处理机制,可以提高系统的并发处理能力

OS 收到中断请求,会打断其他进程的运行,中断处理程序,要尽可能快的执行完,减少对正常进程运行调度的影响

中断处理程序在响应中断时,可能还会「临时关闭中断」,意味着,如果当前中断处理程序没有执行完之前,系统中其他的中断请求都无法被响应,也就说中断有可能会丢失,所以中断处理程序要短且快

再以外卖为例,点了两份不同的外卖,由不同的配送员来配送

当第一份外卖送到时,配送员给我打了长长的电话,说了一些杂七杂八的事情,比如给个好评等等

如果这时另一位配送员也想给我打电话,因为我在通话中(相当于关闭了中断响应),自然就无法打通我的电话,他可能尝试了几次后就走掉了(相当于丢失了一次中断)