#568 使用 nohup 的一个小问题

2021-07-22
function fq () {
    # ...
    nohup qv2ray &>> /tmp/qv2ray.log &
    # ...
}

每次关闭终端,qv2 就一起崩溃了。

然后我改成:

nohup sh -c "qv2ray &>> /tmp/qv2ray.log &"

就好了。

分析:可能是后面日志和改后台运行的部分被 nohup 拿走的缘故吧。

#567 转载:如何将 Numpy 加速 700 倍?用 CuPy 呀

2021-07-21

作为 Python 语言的一个扩展程序库,Numpy 支持大量的维度数组与矩阵运算,为 Python 社区带来了很多帮助。借助于 Numpy,数据科学家、机器学习实践者和统计学家能够以一种简单高效的方式处理大量的矩阵数据。那么 Numpy 速度还能提升吗?本文介绍了如何利用 CuPy 库来加速 Numpy 运算速度。
就其自身来说,Numpy 的速度已经较 Python 有了很大的提升。当你发现 Python 代码运行较慢,尤其出现大量的 for-loops 循环时,通常可以将数据处理移入 Numpy 并实现其向量化最高速度处理。
但有一点,上述 Numpy 加速只是在 CPU 上实现的。由于消费级 CPU 通常只有 8 个核心或更少,所以并行处理数量以及可以实现的加速是有限的。
这就催生了新的加速工具——CuPy 库。

#566 思考:八进制的应用场景

2021-07-21

常见的进制:

  • 二进制, Binary /ˈbaɪnəri/, bin /bɪn/
    除了苏联设计过的一种计算机系统采用了平衡三进制(-1, 0, 1), 所有计算机系统都是采用的二进制, 二进制计算是程序员的一种必备技能, 其重要性不言而喻。
    常见的数字 16(四位), 256(八位), 1024(十位)等。
  • 八进制, Octal /ˈɒktl/, oct /ɒkt/
  • 十进制, Decimal /ˈdesɪm(ə)l/, dec /dek/
    十进制普遍认为是基于人类手指数量来设计的, 其深深的影响了我们的计算方式, 已经作为人类基本的数学认知。
  • 十六进制, Hexadecimal /ˌheksəˈdesɪml/, hex /heks/
    二进制计算机系统中, 一个字节定义为八位, 那么通常的选择是采用两个十六进制数来表示, 在记忆成本和便捷性方面达到一个最好的平衡。
    CPU 位数、地址总线宽度等, 通常是 4 的倍数, 比如:16 位的 8086 / 8088 有 20 位地址总线, 32 位的 386 / 486 / 奔腾 有 32 位地址总线, 64 位酷睿系列有 64 位地址总线。

那么,八进制用来干嘛?

刚才在维基百科上找到了答案:

Octal became widely used in computing when systems such as the UNIVAC 1050, PDP-8, ICL 1900 and IBM mainframes employed 6-bit, 12-bit, 24-bit or 36-bit words.

就是说早期大量机器采用了 6 位,12 位,24 位,36 位的实现,都是 3 的倍数,所以取八进制(3 位二进制数一组)来表示比较通用。

#565 Python 源码学习 04: int

2021-07-20

经过源码分析,可以得知,所有类型的定义都是通过 object.c 中的 INIT_TYPE 语句,比如 INIT_TYPE(&PyLong_Type, "int");

然后,可能是通过 SETBUILTIN("int", &PyLong_Type); 设置成内置方法。

int 类型最后就指向了一个叫做 PyLong_TypePyTypeObject 类型变量。

PyTypeObject

Objects/longobject.c

PyTypeObject PyLong_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "int",                                      /* tp_name */
    offsetof(PyLongObject, ob_digit),           /* tp_basicsize */
    sizeof(digit),                              /* tp_itemsize */
    0,                                          /* tp_dealloc */
    0,                                          /* tp_vectorcall_offset */
    0,                                          /* tp_getattr */
    0,                                          /* tp_setattr */
    0,                                          /* tp_as_async */
    long_to_decimal_string,                     /* tp_repr */
    &long_as_number,                            /* tp_as_number */
    0,                                          /* tp_as_sequence */
    0,                                          /* tp_as_mapping */
    (hashfunc)long_hash,                        /* tp_hash */
    0,                                          /* tp_call */
    0,                                          /* tp_str */
    PyObject_GenericGetAttr,                    /* tp_getattro */
    0,                                          /* tp_setattro */
    0,                                          /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
        Py_TPFLAGS_LONG_SUBCLASS,               /* tp_flags */
    long_doc,                                   /* tp_doc */
    0,                                          /* tp_traverse */
    0,                                          /* tp_clear */
    long_richcompare,                           /* tp_richcompare */
    0,                                          /* tp_weaklistoffset */
    0,                                          /* tp_iter */
    0,                                          /* tp_iternext */
    long_methods,                               /* tp_methods */
    0,                                          /* tp_members */
    long_getset,                                /* tp_getset */
    0,                                          /* tp_base */
    0,                                          /* tp_dict */
    0,                                          /* tp_descr_get */
    0,                                          /* tp_descr_set */
    0,                                          /* tp_dictoffset */
    0,                                          /* tp_init */
    0,                                          /* tp_alloc */
    long_new,                                   /* tp_new */
    PyObject_Del,                               /* tp_free */
};

其中所有的方法就在 PyMethodDef long_methodsPyNumberMethods long_as_number 中。
尤其是 long_as_number 可能就是那些重载操作符的基础。

long_newlong_new_impl

可能是 int 方法对应的实现。

#564 OpenStack 实验环境的快速搭建

2021-07-19

部署方式汇总

  1. 手动部署
  2. 部署脚本,也就是将手动部署的过程转化为脚本
  3. 使用自动化工具部署

而工具又有很多,比如:

  • openstack-chef shields.io
  • openstack-ansible shields.io
    简称 osa
  • puppet
  • Fuel 很早的一个解决方案,
  • Kolla shields.io
    采用 k8s 技术
  • DevStack shields.io
  • PackStack shields.io
    来自红帽的 rdo 项目,用于 OpenStack 在 RHEL 系统上的部署。

以最新的 wallaby 为例。

通过 DevStack 来弄。

就体验来说,在 devstack 的使用上,有需要改进的地方:

  1. 离线安装(提前准备好安装包和仓库)
  2. 出现异常的重试
  3. 日志还是写到文件中去的好
  4. 进度不友好

如果要开发有一定规模的相关项目,还是自己维护一组脚本,或者定制某个部署工具比较合适。

#563 我不喜欢通过视频学习

2021-07-19

最近看了腾讯课堂和开课吧的几个 IT 方面的教学课程,都是视频 + 资料分享,可能还有课后作业之类的。

最后我的感受就是,这种学习方法非常不适合我,有可能是不适合大多数人。

如果我看书,当然,应该是合适的书,效率会更高。我浏览目录就可以知道应该重点看哪里,而跳过我知道的,或者对我帮助不大的地方,而现在的视频却很难做到通过一个大纲来实现跳转。更要命的是培训方希望教学能够覆盖更多的人,往往在一些基础知识方面花费太大力气,而直播又无法跳过,简直是谋财害命。更更要命的是,经常在深入之后,对正式的专业知识的讲解,进度又拉的很快,几句话带过(可能体验课也就只能这样吧)。

我也看到有一些课程是类似抖音短视频的风格,一个短视频一个知识点,然后通过播放列表可以实现跳转,我觉得这种方式会好的多。

经过反复思考,我觉得适合我的学习方式,还是先整理出一个大纲,然后找到合适的资料,一边看资料,一边敲代码。
如果有第三方组织真的有真材实料,然后可以给我合理的建议,设计出恰当的学习计划,给我做答疑和指导,我会付费,价格合理的话。
在自学方面,往往会摸索很久才会找到一条合适的路,如果可以得到正确的引导,那么效率就会提升很多。

#562 requests 遇到的错误:Failed to parse

2021-07-15

今天使用 requests 时发现居然报错:Failed to parse: http://xxxxx

重要的是我不是直接是用 requests,而是使用另一个工具库,然后它来使用 requests 发起网络请求,所以我就完全没有想到着一层。更重要的是代码之前运行的好好的,没有任何问题。而且 requests 这样一个通用的库,谁能想到它会有问题呢?

我怀疑了好多情况,比如防火墙,代理,网络环境等等,但是没有找到原因。最后开始看工具库的源码,看到头都大了,也没有一点发现。

最后还是在 StackOverflow 上看到有人提醒,可能是 requests 下面的 urllib3 依赖里面有点什么问题,建议先升级一下看看。一试果然好了。

我没有仔细分析其具体原因,留给记录,下次遇到类似问题要小心。

#561 redis 批处理

2021-07-15

先将命令写在 commands.txt 中,一行一个,不用分号结尾,然后:

echo commands.txt | redis-cli -h 127.0.0.1 -p 6379

#560 scp 拷贝文件引发的一次故障

2021-07-15

背景:有一个服务会定时读某个目录下的文件,然后逐个进行处理。

今天出于某些原因,我通过 scp 拷贝文件到那个目录下,结果意外的发现服务挂掉了,就是因为读到了一个空文件,抛出一个没有被处理的错误。

我知道这是程序设计上存在的一个缺陷,但之前我们一直通过 rsync 在传输文件,从来没有遇到过这样的问题。

我查了文档并进行了实验,确认了 rsync 会在文件传输时创建一个 .文件名.随机串 的临时文件,然后在传输完成后重命名。而 scp 则不会这样做,它会创建空文件,然后逐渐填充内容。

If the target file does not yet exist, an empty file with the target file name is created, then filled with the source file contents. No attempt is made at "near-atomic" transfer using temporary files.

我的理解是,文档里面说的 near-atomic 应该就是指 rsync 那种模式,而 atomic 的意思应该是指连临时文件都不用创建的模式。也不知道有什么文件系统支持这种模式。