2017年8月

这两天读了一下Python的Condition实现源码,是实现Queue的工具之一,发现是非常朴素的sleep->loop->query模式。源码很少,直接贴出,就不做注释了:)

def wait(self, timeout=None):
        """Wait until notified or until a timeout occurs.
 
        If the calling thread has not acquired the lock when this method is
        called, a RuntimeError is raised.
 
        This method releases the underlying lock, and then blocks until it is
        awakened by a notify() or notifyAll() call for the same condition
        variable in another thread, or until the optional timeout occurs. Once
        awakened or timed out, it re-acquires the lock and returns.
 
        When the timeout argument is present and not None, it should be a
        floating point number specifying a timeout for the operation in seconds
        (or fractions thereof).
 
        When the underlying lock is an RLock, it is not released using its
        release() method, since this may not actually unlock the lock when it
        was acquired multiple times recursively. Instead, an internal interface
        of the RLock class is used, which really unlocks it even when it has
        been recursively acquired several times. Another internal interface is
        then used to restore the recursion level when the lock is reacquired.
 
        """
        if not self._is_owned():
            raise RuntimeError("cannot wait on un-acquired lock")
        waiter = _allocate_lock()
        waiter.acquire()
        self.__waiters.append(waiter)
        saved_state = self._release_save()
        try:    # restore state no matter what (e.g., KeyboardInterrupt)
            if timeout is None:
                waiter.acquire()
                if __debug__:
                    self._note("%s.wait(): got it", self)
            else:
                # Balancing act:  We can't afford a pure busy loop, so we
                # have to sleep; but if we sleep the whole timeout time,
                # we'll be unresponsive.  The scheme here sleeps very
                # little at first, longer as time goes on, but never longer
                # than 20 times per second (or the timeout time remaining).
                endtime = _time() + timeout
                delay = 0.0005 # 500 us -> initial delay of 1 ms
                while True:
                    gotit = waiter.acquire(0)
                    if gotit:
                        break
                    remaining = endtime - _time()
                    if remaining <= 0:
                        break
                    delay = min(delay * 2, remaining, .05)
                    _sleep(delay)
                if not gotit:
                    if __debug__:
                        self._note("%s.wait(%s): timed out", self, timeout)
                    try:
                        self.__waiters.remove(waiter)
                    except ValueError:
                        pass
                else:
                    if __debug__:
                        self._note("%s.wait(%s): got it", self, timeout)
        finally:
            self._acquire_restore(saved_state)

前段时间买了一个树莓派,最初的想法是可以用来挂一些下载,或者挂一些爬虫,做做简单的NAS之类的。

最后到手之后,发现树莓派3 B+还是很快的,4个CPU核心+1G RAM,外接移动硬盘的情况下,IO上也可以接受。

添加风扇控制

我从淘宝上弄了一个风扇,直接接到树莓派的5v-0v接口上,这样风扇会一直运转,其实还挺烦的……因为声音比较大……所以希望风扇能在温度低于45度的时候,能够自动关闭就好了。

首先参考如下篇文章,接好一个三极管,并将三极管的P级接到树莓派的GPIO 12针脚。

在树莓派上启用软件PWM控制风扇(Shell脚本版)
http://www.zhangminghao.com/post/43.html

树莓派用开关三极管控制散热风扇
http://yshblog.com/blog/55

树莓派的PWM功能我参考了一下,但是调试之后无效,可能是我的三极管问题,或者接线没接好。

参考RPi.GPIO 0.5.2a now has software PWM – How to use it

http://raspi.tv/2013/rpi-gpio-0-5-2a-now-has-software-pwm-how-to-use-it

所以最后,我做了风扇自动开启和关闭的功能,但是没做自动调速功能。

项目在Github: PIFanTuner https://github.com/winkidney/PIFanTuner

直接下载下来,运行

sudo python setup.py install
./install-systemd-file.sh

[Unit]
Description=Remote desktop service (VNC)
After=syslog.target network.target

[Service]
Type=forking
User=pi
ExecStartPre=/bin/sh -c '/usr/bin/tightvncserver -kill :i > /dev/null 2>&1 || :'
ExecStart=/usr/bin/tightvncserver  :1
ExecStop=/usr/bin/tightvncserver -kill :1

[Install]
WantedBy=multi-user.target

然后运行

sudo systemctl daemon-reload
sudo systemctl enable vnc-server@1
sudo systemctl start vnc-server@1

然后,在Windows/linux/Mac上下载一个tightvnc viewer, 使用 your_ip_or_host:5901 ,就可以连接到VNC服务器了,以后每次开启树莓派,服务也会自动启动。

连接到隐藏的无线网络

树莓派使用lxde-panel 并没有连接到无线网络的功能。

参考noob wifi with hidden ssid

在命令行键入 sudo iwlist wlan0 scan essid *yourSSID* 即可在无线列表中找到隐藏了ID的无线,点击一下连接即可。

搭建下载环境

搭建下载环境,可以参考 Raspberry Pi从零开始搭建低成本NAS(7)-Aria2远程下载,
http://mkitby.com/2016/01/15/raspberry-pi-nas-remote-download-aria2/

最后的aria2 web-ui我选择了webui-aria2

引子

以前对Gevent(Greenlet)为什么比Thread快,只有一个隐约的理解,之前的看到过的说法是,上下文切换的成本上,Greenlet比Thread低很多,但是具体低在哪些地方呢?

刚好这段时间阅读了CSAPP,对这个问题又有了新的看待的角度:)

参考了如下三篇文章和greenlet的实现:

https://www.ibm.com/developerworks/cn/linux/kernel/l-thread/

http://stackoverflow.com/questions/15556718/greenlet-vs-threads

http://www.jianshu.com/p/cd41c14b19f4

Greenlet VS Thread

相同点

都进行了寄存器内容的保存,保存了栈的内容以便将来恢复
不同点

如下几件事情,是协程切换不用做的事情

少了一些system call,自己主动保存/恢复寄存器信息。
不需要管理复杂的线程数据结构然后再到Python VM里面管理字节码,比如CLONE_FS,CLONE_FILES,CLONE_SIGHAND等操作都不需要进行
没有mmap操作
综上所述,协程的创建和上下文切换成本中,两者都需要进行寄存器状态保存,但用户态的协程,少了很多额外操作,因此更加轻量。

DC/OS 配置记录

这段时间有机会玩了一下DC/OS,配置细节中还有相当多不完善的地方,安装方面的健壮性还有待提升。

可以先看这里了解一下DC/OS 和Mesos是干嘛的 。

然后跟着https://docs.mesosphere.com/1.8/administration/installing/custom/cli/

进行安装。

安装DC/OS的过程遇到的问题主要有两类:

安装过程前置没有达到条件,缺乏检测手段。
像docker 是有 docker-env-check的。

前置的安装条件检测,软件部分需要仔细check,自己需要手工安装。

https://docs.mesosphere.com/

选择很多,但是最后发现可选的其实只有CLI安装(GUI安装不能cover需求)

  1. 启动脚本没有考虑极端网络条件(比如虚拟机)

因为我的环境是四台KVM虚拟机,都是从同一个物理网卡发出数据包,所以路由器会进行一次ICMP Redirect,恰好在DC/OS 的服务启动脚本里有一个ping master的前置条件,使用了 ping -c1 master.mesos,导致ping命令失败。

ping 命令只发送一个包的的时候,会直接失败

$ ping -c1 -vv master.mesos
ping: socket: Permission denied, attempting raw socket...
PING master.mesos (10.155.0.212) 56(84) bytes of data.
From gateway (10.155.0.1): icmp_seq=1 Redirect Host(New nexthop: 10.155.0.212 (10.155.0.212))
Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst Data
 4  5  00 5400 1216   0 0040  40  01 b80d 10.155.0.214  10.155.0.212 
From gateway (10.155.0.1) icmp_seq=1 Redirect Host(New nexthop: 10.155.0.212 (10.155.0.212))

--- master.mesos ping statistics ---
1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms

icmp redirect 参考

http://www.cisco.com/c/en/us/support/docs/ip/routing-information-protocol-rip/13714-43.html

When Are ICMP Redirects Sent?

Cisco routers send ICMP redirects when all of these conditions are
met:

The interface on which the packet comes into the router is the same
interface on which the packet gets routed out. The subnet or network
of the source IP address is on the same subnet or network of the
next-hop IP address of the routed packet. The datagram is not
source-routed. The kernel is configured to send redirects. (By
default, Cisco routers send ICMP redirects. The interface subcommand
no ip redirects can be used to disable ICMP redirects.)