第 45 期:杭州的周末能不下雨吗?
@Author : Lewis Tian (taseikyo@gmail.com)
@Link : github.com/taseikyo
@Range : 2021-09-05 - 2021-09-11
Weekly #45
本文总字数 2165 个,阅读时长约:4 分 16 秒,统计数据来自:算筹字数统计。

*Photo by Janine Robinson on Unsplash
她彷徨在这寂寥的雨巷,撑着油纸伞像我一样,像我一样地默默彳亍着,冷漠,凄清,又惆怅。 —— 戴望舒《雨巷》
Table of Contents
NetBSD Explained: The Unix System That Can Run on Anything
golang-redis 判断 key 不存在还是读取出错
golang-redis 分布式自旋锁
使用 GitHub Actions 将仓库里的 Markdown 文件定时发到推特
本地运行 GitHub Actions
杭州的周末能不下雨吗?
algorithm 🔝
review 🔝
什么是 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,专注于安全性和代码正确性。
tip 🔝
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 链接时的超时。
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、内存版
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
挺棒的一个东西,在本地运行就可以确定是否写对了,可以不必像之前一次次推送来验证。
share 🔝
1. 杭州的周末能不下雨吗?
来了杭州两个多月,几乎每周末都会下雨,好不容易到周末,本以为可以约两三好友出来吃饭,结果来这么一出,谁下雨愿意出门啊,下雨不是更适合睡觉吗?
这周末又与往常一般下雨了,还好今天中午雨停了,于是跟同学一起去大运河逛了圈,之后去武林广场吃了烤肉,虽然中途下雨了,但是吃完就没下了。
烤肉还不错,虽然走了一下午很累,但是吃的很快乐。
吃完回来的时候路过一家店,第一眼看错了名字,感觉老板也太嚣张了,旁边就是警察叔叔啊,再看一眼原来是我看错了,主要是这名字有点怪(

另外,手机掉电太离谱了,出地铁站还剩 4%,差点以为要自动关机了,搞得我在地铁上都不敢玩了,果然该换电(手)池(机)了!
最后更新于
这有帮助吗?