@Author : Lewis Tian (taseikyo@gmail.com)
@Link : github.com/taseikyo
@Range : 2021-09-05 - 2021-09-11
Weekly #45
readme | previous | next
本文总字数 2165 个,阅读时长约:4 分 16 秒,统计数据来自:算筹字数统计。
*Photo by Janine Robinson on Unsplash
她彷徨在这寂寥的雨巷,撑着油纸伞像我一样,像我一样地默默彳亍着,冷漠,凄清,又惆怅。 —— 戴望舒《雨巷》
Table of Contents
review
NetBSD Explained: The Unix System That Can Run on Anything
tip
golang-redis 判断 key 不存在还是读取出错
使用 GitHub Actions 将仓库里的 Markdown 文件定时发到推特
什么是 NetBSD?
NetBSD 是一个开源的操作系统,与 Linux 一样,NetBSD 致力于与 Unix 的广泛兼容性,提供类似的实用程序和行为。
NetBSD 是基于 BSD 版本(Berkeley Software Distribution)的 Unix,因此名称中有 “BSD”。它是 20 世纪 90 年代早期支持 pc 的 386/BSD 版本的一个分支。
FreeBSD 侧重于 PC 平台,OpenBSD 侧重于安全性,NetBSD 侧重于不同平台的可移植性。虽然 NetBSD 看起来像另一个 Linux 发行版,但是整个系统,包括内核和用户实用程序,是作为一个整体一起开发的。这与 Linux 发行版拼凑来自多个源的组件的方式形成了鲜明的对比。
BSD 最初是基于贝尔实验室的 Unix 系统,但多年来与其母公司 AT&T 的版本分道扬镳,因此可以发布一个不包含 AT&T 代码的版本。
虽然它不是一个完整的操作系统,但这个“网络版”之所以这么命名,是因为它包含了几个公司用来在他们的产品中实现网络的 TCP/IP 网络代码。它甚至最终进入了微软的 Windows 系统。
随着英特尔 80386 处理器的出现,个人电脑变得更加强大,William joritz 将 BSD 移植到 386 处理器,使用网络版本作为起点,他发布了 386BSD。Jolitz 很难跟上其他开发人员为改进系统而发送给他的所有补丁,所以项目的分支立即出现了。
一个小组希望继续改进 PC 版本,而另一个小组则希望关注不同体系结构之间的可移植性。前者成为 FreeBSD,后者成为 NetBSD。
当开发人员 Theo de Raadt 被要求从 NetBSD 项目中辞职后,NetBSD 又被迫离开,随后他创建了一个变体 OpenBSD,专注于安全性和代码正确性。
redis 中有一个特殊值(redis.Ni
)用来判断读取时 key 不存在的情况:
// 判断 key 是否存在
val, err := client.Get("user:zhangyunfeiVir").Result()
if err == redis.Nil {
fmt.Println("key2 does not exist")
} else if err != nil {
panic(err)
} else {
fmt.Println("读取:", val)
}
1、使用 redis 的 setnx 实现了一个自选锁,有 key 超时,同时也有我们调用 redis 链接时的超时。
spin_lock_setnx.go
type Lock struct {
resource string
value interface{}
timeout time.Duration
redisCli *redis.ClusterClient //这个是链接redis集群的cli,可以自行修改
}
func NewRedis(redisCli *redis.ClusterClient, resource string, value interface{}, timeOut time.Duration) *Lock {
return &Lock{
resource: resource,
value: value,
timeout: timeOut,
redisCli: redisCli,
}
}
func (lock *Lock) TryLock() (ok bool, err error) {
ok, err = lock.redisCli.SetNX(lock.resource, lock.value, lock.timeout).Result()
//log.Printf("resource:%s, timeout:%v, ok:%v, err:%v\n", lock.resource, lock.timeout, ok, err)
return
}
func (lock *Lock) Unlock() (err error) {
err = lock.redisCli.Del(lock.resource).Err()
return
}
func (lock *Lock) SpinLockUntilTimeOut(ctx context.Context, d time.Duration) (timeOut bool, err error) {
var (
now time.Time
ok bool
)
endTime := time.Now().Add(d)
for {
select {
case <-ctx.Done():
timeOut = true
//log.Printf("SpinLockUntilTimeOut at ctx.Done()")
return
default:
now = time.Now()
if now.After(endTime) {
timeOut = true
//log.Printf("SpinLockUntilTimeOut at d")
return
}
ok, err = lock.TryLock()
if err != nil {
return
}
if ok {
return
} else {
runtime.Gosched()
}
}
}
}
2、内存版
spin_lock_memory.go
var lockers map[string]map[uint64]chan interface{}
var addLock chan lockImpl
var delLock chan lockImpl
var tranceId uint64
type lockImpl struct {
delId uint64
addId chan uint64
wait chan interface{}
key string
}
func init() {
lockers = make(map[string]map[uint64]chan interface{})
addLock = make(chan lockImpl)
delLock = make(chan lockImpl)
run()
}
func run() {
go func() {
var (
ok1, ok2 bool
addLs, delLs map[uint64]chan interface{}
)
for {
select {
case add := <-addLock:
if addLs, ok1 = lockers[add.key]; !ok1 {
addLs = make(map[uint64]chan interface{})
}
tranceId++
addLs[tranceId] = add.wait
lockers[add.key] = addLs
add.addId <- tranceId
close(add.addId)
if len(addLs) == 1 {
add.wait <- struct{}{}
close(add.wait)
}
case del := <-delLock:
if delLs, ok2 = lockers[del.key]; ok2 {
delete(delLs, del.delId)
for _, v := range delLs {
v <- struct{}{}
close(v)
break
}
}
}
}
}()
}
type Memory struct {
key string
id uint64
}
func (m *Memory) SLock(ctx context.Context) (timeOut bool, err error) {
l := lockImpl{
addId: make(chan uint64, 1),
wait: make(chan interface{}, 1),
key: m.key,
}
addLock <- l
m.id = <-l.addId
select {
case <-l.wait:
return
case <-ctx.Done():
timeOut = true
return
}
}
func (m *Memory) UnSLock() (err error) {
l := lockImpl{
delId: m.id,
key: m.key,
}
delLock <- l
return
}
func NewMemory(path string) *Memory {
return &Memory{
key: path,
}
}
3. 使用 GitHub Actions 将仓库里的 Markdown 文件定时发到推特
拿到 twitter 的各个 key,然后利用 GitHub Actions 读取 README 来发送 twitter,感觉本质上是一种爬虫。
4. 本地运行 GitHub Actions
挺棒的一个东西,在本地运行就可以确定是否写对了,可以不必像之前一次次推送来验证。
1. 杭州的周末能不下雨吗?
来了杭州两个多月,几乎每周末都会下雨,好不容易到周末,本以为可以约两三好友出来吃饭,结果来这么一出,谁下雨愿意出门啊,下雨不是更适合睡觉吗?
这周末又与往常一般下雨了,还好今天中午雨停了,于是跟同学一起去大运河逛了圈,之后去武林广场吃了烤肉,虽然中途下雨了,但是吃完就没下了。
烤肉还不错,虽然走了一下午很累,但是吃的很快乐。
吃完回来的时候路过一家店,第一眼看错了名字,感觉老板也太嚣张了,旁边就是警察叔叔啊,再看一眼原来是我看错了,主要是这名字有点怪(
另外,手机掉电太离谱了,出地铁站还剩 4%,差点以为要自动关机了,搞得我在地铁上都不敢玩了,果然该换电(手)池(机)了!
readme | previous | next