#906 数学:小圆沿着大圆滚动

2023-07-22

阮一峰博客上看到这么一个数学题(原文是 maths.org 2014 年的一篇文章):

已知:小圆的半径为 $r$,大圆的半径为 $4r$
:小圆自身滚动了几周?

#905 转载:成年期的快与慢

2023-07-21

我们生活在这样一个社会:小孩子像成年人一样老成,而成年人像小孩子一样幼稚

现在的孩子们比以前更容易接触到成年人的世界,因此他们更早成人化。

从很小的年龄起,他们就在视频网站观看暴力战争,在社交网络上看到性感和暴露的照片和视频。

然而,当孩子们成年以后,他们往往无法实现经济独立,也没有机会承担足够的责任

结果,整个社会的文化就变得很幼稚,成年人感到无法做出承诺,即使承诺了也缺乏信心,对以后的生活感到难以把握。

他们的行事方式和处事态度,就像还在青少年时期。

#904 F12 网络过滤器

2023-07-16

示例

mime-type:image/png larger-than:1K
# Edge 官方示例,表示过滤出大于 1K 的 PNG 图片

domain:*.csdn.net method:POST
# 过滤出 CSDN 域的 POST 请求。

has-response-header:Content-Type -domain:*.baidu.com
# 过滤出带 Content-Type 头的请求,排除百度域。

清单

属性 详情
domain 仅显示来自指定域的资源。您可以使用通配符(*)来包含多个域。
例如,*.com 会显示所有以 .com 结尾的域名资源。
DevTools 会将所有找到的域名填充到自动完成下拉菜单中。
has-response-header 显示包含指定 HTTP 响应头的资源。
DevTools 会将所有找到的响应头填充到自动完成下拉菜单中。
is 使用 is:running 查找 WebSocket 资源。
larger-than 显示大于指定大小的资源,单位为字节。
设置值为 1000 相当于设置值为 1k
method 显示通过指定的 HTTP 方法类型检索的资源。
DevTools 会将所有找到的 HTTP 方法填充到下拉菜单中。
mime-type 显示指定 MIME 类型的资源。
DevTools 会将所有找到的 MIME 类型填充到下拉菜单中。
mixed-content 显示所有混合内容资源(mixed-content:all),或仅显示当前显示的资源(mixed-content:displayed)。
scheme 显示通过不安全的 HTTP(scheme:http)或安全的 HTTPS(scheme:https)检索的资源。
set-cookie-domain 显示具有与指定值匹配的 Set-Cookie 标头中的 Domain 属性的资源。
DevTools 会将所有找到的 Cookie 域填充到自动完成中。
set-cookie-name 显示具有与指定值匹配的 Set-Cookie 标头中的名称的资源。
DevTools 会将所有找到的 Cookie 名称填充到自动完成中。
set-cookie-value 显示具有与指定值匹配的 Set-Cookie 标头中的值的资源。
DevTools 会将所有找到的 Cookie 值填充到自动完成中。
status-code 显示与特定 HTTP 状态码匹配的资源。
DevTools 会将所有找到的状态码填充到自动完成下拉菜单中。
  1. 多个条件之间是 AND 关系,OR 关系暂时不支持。
  2. 前面加上 - 表示取反,小技巧:可以通过输入 - 之后的自动补全查看所有支持的选项。

参考资料与拓展阅读

#903 软件开发中的“上游”与“下游”

2023-07-13

类比到河流,上游和下游概念就非常明确,水从上游往下游流动。

在工业生产车间中,不同工序就组成一条河流,流动的产品,前面的工序是上游,后面的工序是下游。
下游依赖上游。

在软件设计中,不同服务(SOA、微服务)组成一条河流,流动的是数据,先处理数据的是上游,后处理数据的是下游。
下游依赖上游。
注意:数据是怎么个流动方式的不重要,可能是上游推的,可能是下游拉的。上游和下游之间可能会互相调用 API,这个也不影响数据的依赖关系。
总之,上游靠近入口网关,下游靠近出口网关。

开源项目中,fork 关系组成一条河流,流动的是代码,被 fork 的项目是上游,fork 出来的项目是下游。
下游依赖上游。
当然,下游的代码更新也可能会反馈到上游。

#902 转载:美国最具争议的问题,哈佛为何败诉?

2023-07-11

两周前,美国社会向来最具争议的政策之一——自上世纪 60 年代开始践行的“平权法案”(Affirmative Action)被推翻。

美国最高法院针对涉及哈佛大学和北卡罗莱纳大学被控在招生时考虑种族比例的案件裁定,宪法禁止大学在招生过程中考虑申请人的种族因素。这一判决被视作自推翻堕胎权判例后又一次历史性裁决,也有观点指出,这一裁决更多体现美国最高院保守派压倒性势力以及保守主义的全面回归。

看理想两位节目主讲人庞颖、詹青云,关于此次平权法案被推翻特别录制了一期番外,延续《思辨力 35 讲》的节目形式,庞颖和詹青云分别从支持者、反对者的两方立场就平权法案的争议与利弊进行了一场辩论。问题不仅关乎种族正义、教育平等,也关乎社会的公正与良善。

#901 PEP 703 提案

2023-07-11

Python 内部的 GIL(全局解释器锁)使 Python 的多线程开发变得更加简单,避免了大部分竞争条件,但是限制了 Python 进程使用多核心处理器,所有需要并行的场景全部受限。
官方建议,如果需要用到多核,那就选择多进程编程。

Python 出现的时候还没有多核 CPU,而现在多核心早就成为了主流,4 核、8 核太常见了。

因此从来不乏移除 GIL 的声音,不过没有一次成功。要想不对现有的项目造成太大的影响简直难于登天。
PS:几年前有一个叫做 Gilectomy 的项目(GIL Ectomy,GIL 切除术)因为导致 Python 性能下滑严重而失败。

最大的挑战是要保持对现有代码的兼容性,保住基本盘,也就是容易上手,容易开发。

  • 2021 年,香农计划成员 Eric Snow 提交 PEP 684 A Per-Interpreter GIL(每个解释器一个 GIL)。
    这应该是一个比较稳妥的方案,但我怀疑性价比是否足够。
    PS:和下面提到的 nogil 方案不冲突。

  • PEP 683 – Immortal Objects, Using a Fixed Refcount

  • PEP 554 – Multiple Interpreters in the Stdlib

  • 2021 年,Meta(Facebook)开发者 Sam Gross 基于 Python 3.9 创建了一个 nogil 的分支,最终证明了这个方案技术上可行,相较于 Gilectomy 单核性能没有收到太大的影响,拓展性也不错。

  • 2022 年 5 月,Sam Gross 在 Python 语言峰会上介绍了他的 nogil 项目,提议移除 GIL。
  • 2023 年 1 月,Sam Gross 又提交了一份新的提案 PEP 703 Making the Global Interpreter Lock Optional in CPython(使 GIL 成为可选项)。

现在是最接近移除 GIL 的时刻。
如果顺利通过,几年之后,我们就能用上没有 GIL 的 Python。

问题

  1. PEP 703 引入 --disable-gil 来创建一个没有 GIL 的 Python 版本。
    但是会导致以后部分 Python 库的开发需要提供两种包文件,运行在 nogil 上的版本,和运行在 GIL 上的版本。

参考资料与拓展阅读

#899 Go 1.21 for 语义变更

2023-07-05

仔细观察下面的例子就能知道问题在哪里了:

例子 1

package main

import "fmt"

func main() {
    items := []int{1, 2, 3}

    {
        var all []*int
        for _, item := range items {
            all = append(all, &item)
        }
        fmt.Printf("%+v\n", all)
        // [0xc00008c018 0xc00008c018 0xc00008c018]
        // 输出的都是最后一个值!!!
        for _, i := range all {
            fmt.Printf("%+v, %+v\n", i, *i)
        }
    }

    // fix it:
    {
        var all []*int
        for _, item := range items {
            item := item // 重点
            all = append(all, &item)
        }
        for _, i := range all {
            fmt.Printf("%+v, %+v\n", i, *i)
        }
    }
}

例子 2

package main

import "fmt"

func main() {
    {
        var prints []func()
        for _, v := range []int{1, 2, 3} {
            prints = append(prints, func() { fmt.Println(v) })
        }
        for _, print := range prints {
            print()
        }
    }
    // 输出的是 3 3 3,而不是 1,2,3,Why?

    // fix it:
    {
        var prints []func()
        for _, v := range []int{1, 2, 3} {
            v := v // 重点
            prints = append(prints, func() { fmt.Println(v) })
        }
        for _, print := range prints {
            print()
        }
    }
}

例子 3

package main

import (
    "fmt"
    "sync"
)

func main() {
    items := []int{1, 2, 3}

    {
        wg := sync.WaitGroup{}
        for _, v := range items {
            wg.Add(1)
            go func() {
                // 会提示:loop variable v captured by func literal
                fmt.Println(v)
                wg.Done()
            }()
        }
        wg.Wait()
    }

    // fix it:
    {
        wg := sync.WaitGroup{}
        for _, v := range items {
            wg.Add(1)
            v := v // 重点
            go func() {
                fmt.Println(v)
                wg.Done()
            }()
        }
        wg.Wait()
    }
}

这个例子可以改写成:

package main

import (
    "fmt"
)

func main() {
    items := []int{1, 2, 3}
    done := make(chan bool)
    {
        for _, v := range items {
            go func() {
                // 会提示:loop variable v captured by func literal
                fmt.Println(v)
                done <- true
            }()
        }
        for _ = range items {
            <-done
        }
    }

    // fix it:
    {
        for _, v := range items {
            v := v // 重点
            go func() {
                fmt.Println(v)
                done <- true
            }()
        }
        for _ = range items {
            <-done
        }
    }
}

我的理解

根据 Go 的设计思想,花括号内是一个独立的作用域,for 循环每一次也应该是独立的。
当前这次循环中的变量和上一次循环的变量应该是不一样的。
但实际上,根据运行结果来看,他们的地址是一样的。

闭包函数应该也是这样的,去原来的位置读相关变量,但是之前的位置写入了新的值。

这个设计是一个大坑,对于新人非常不友好。

从 1.21 开始支持根据环境变量 GOEXPERIMENT=loopvar 来启用新的订正版语义。
从 1.22 开始正式修改 for 语义。

Russ Cox 认为当前语义的代价很大,出错的频率高于正确的频率。

但是这次变更 for 语句语义的决定和之前的承诺有冲突(保证兼容性的基础就是语义不会被重新定义)。
但是好在 Go 已经为这种情况做好了足够的准备,即,go 支持在同一批编译中,按照不同包的 mod 文件中声明的 go 版本来对体现不同的语法特性。
就比如 A 包需要 1.22,然后依赖 B 包,需要 1.18,那么 A 包中的代码按照新的定义来,B 包中的代码按照旧的定义来。

https://github.com/golang/go/discussions/56010

#898 卡拉马佐夫兄弟

2023-07-04

卡拉马佐夫兄弟

《卡拉马佐夫兄弟》(俄语:Бра́тья Карама́зовы、英语:The Brothers Karamazov)是俄罗斯作家陀思妥耶夫斯基创作的最后一部长篇小说,通常也被认为是他一生文学创作的巅峰之作。这部宏篇巨制在经历了《俄国导报》上两年的连载后,于 1880 年完成。他曾构想将其作为他的一部更宏大的作品《一个伟大罪人的一生》(The Life of a Great Sinner)的第一部分,然而未能如愿,他在《卡拉马佐夫兄弟》完成后仅四个月就辞世了。

我没有看过这本书,但是看到这句话还是挺触动的:

要爱具体的人,不要爱抽象的人。 > 要爱生活本身,不要爱生活的意义。

罗翔的阐述

知识分子的一个经常性的倾向,就是我们喜欢抽象概念,我们胜过具象的事物,
但是一个越爱抽象人的人往往难对具象的人表现关爱。
因为抽象的人是美好的,抽象的人存在于理念之间,而具体的人都是有缺陷的。所以这就是为什么你越是感到抽象人的美好,你越会发现具体人,你身边人的可恶,可鄙,可耻。

小故事

记得我小的时候看过一个小故事,讲的是一个小孩,清晨起床之后,安安静静的坐着思考今天要为爸爸、妈妈、弟弟做点什么,但是爸爸、妈妈、弟弟逐个过来找他帮忙的时候,他每次都不耐烦的说:我在思考呢!

参考资料与拓展阅读

#897 Windows 10 开发环境重装笔记

2023-07-03

基础环境:Windows 10 (带 Edge)

  1. 驱动更新

  2. 激活

  3. Windows 更新
    PS:系统更新之后就会有 winget 了

  4. 用户目录下的文件夹链接到移动磁盘
    视频,图片,文档,下载,音乐

  5. 360 “优化” 一番

  6. 360安全卫士

  7. 驱动大师
  8. 360压缩

  9. 复制目录 .ssh, .config 目录

  10. 配置网络代理 + 办公网络 VPN

  11. 安装软件

winget 在 msstore 中叫做“应用安装程序”
Windows Terminal 也可以在 msstore 中找到

winget install Microsoft.VisualStudioCode
winget install Microsoft.Edge
winget install Microsoft.WindowsTerminal

winget install Git.Git
winget install qishibo.AnotherRedisDesktopManager # 导入配置即可
winget install ScooterSoftware.BeyondCompare4
winget install KeePassXCTeam.KeePassXC
winget install Apifox.Apifox

# winget install Tencent.wechat-work
winget install Tencent.WeCom
winget install Tencent.WeChat

winget install Python.Python.3.8
winget install GoLang.Go

winget install voidtools.Everything
winget install hluk.CopyQ

winget install Nutstore.Nutstore
winget install NetEase.YoudaoNote # 有道云笔记
winget install NetEase.CloudMusic # 有道云音乐

# winget install iFlytek.iFlyIME # 讯飞输入法
winget install Rime.Weasel # 小狼毫输入法(Rime)

# 无需安装,走笔记本中转
# winget install OpenVPNTechnologies.OpenVPNConnect

其他软件:

  • Filezilla Client

无需安装:

  • GFW,走笔记本中转
  • HeidiSQL(Portable 版本)

Edge 浏览器

  1. 自动更新:... > 帮助与反馈 > 关于 Microsoft Edge
  2. 登录账号,自动同步
  3. 同步需要一段时间,可以先安装上 SwitchyOmega:
    https://microsoftedge.microsoft.com/addons/search/switchyomega?hl=zh-CN

VSCode

  1. 登录账号,自动同步
  2. 同步需要一段时间,可以先安装上 Remote - SSH

Windows Terminal

  1. 配置上开发机器的 SSH 连接,作为默认会话
  2. 记住 GitBash 的快捷键

访问开发机器 zsh 的时候,Home / End 失灵,只能 Ctrl + A / Ctrl + E 代替。

  1. bash 没有问题
  2. Putty 连接 zsh 也是好的

经过一番实验,发现使用 Git 带的 ssh 就好了:

# C:\Windows\System32\OpenSSH\ssh.exe
C:\Users\Administrator>ssh -V
OpenSSH_for_Windows_7.7p1, LibreSSL 2.6.5

# C:\Program Files\Git\usr\bin\ssh.exe
C:\Users\Administrator>"C:\Program Files\Git\usr\bin\ssh.exe" -V
OpenSSH_9.0p1, OpenSSL 1.1.1p  21 Jun 2022

# 作为对照,这是开发机器 (Ubuntu 22.10) 上的 SSH 版本:
ssh -V
OpenSSH_8.9p1 Ubuntu-3ubuntu0.1, OpenSSL 3.0.2 15 Mar 2022
"C:\Program Files\Git\usr\bin\ssh.exe" markjour@172.16.0.49 -F C:\Users\Administrator\.ssh\configwin

Git Bash

~/.bash_profile

test -f ~/.profile && . ~/.profile
test -f ~/.bashrc && . ~/.bashrc

~/.bashrc

source ~/Projects/StdEnv/aliases/main.sh

旧磁盘格式化 + 反复覆写

dd if=/dev/zero of=/e/bigfile bs=10M