引子

以前对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.)

老坑,现在来填掉:)

之前做一个需求,是需要解析Flask里的URL Rule里的参数名字和类型,用来自动生成命令行内的Rest Client的参数。

Rule:  /disks/<int:disk_id>

需要得到参数: disk (type int)

解铃还须系铃人,直接看Flask源码吧:),看看它是如何管理/解析用户在 route 内添加的URL Parttern的.

首先,一路跟踪下去找到源码里的函数吧~~

from flask import Flask
 
app.route()

从 app.py中,可以看到

url_rule_class = Rule()

搜索parse 关键字,可以找到 parse_rule 函数,让我们一起来看看parse_rule函数吧:)

为了将parse_rule和 flask解耦,我拆出了以下代码。

import re

_rule_re = re.compile(r'''
    (?P<static>[^<]*)                           # static rule data
    <
    (?:
        (?P<converter>[a-zA-Z_][a-zA-Z0-9_]*)   # converter name
        (?:\((?P<args>.*?)\))?                  # converter arguments
        \:                                      # variable delimiter
    )?
    (?P<variable>[a-zA-Z_][a-zA-Z0-9_]*)        # variable name
    >
''', re.VERBOSE)


def parse_rule(rule):
    """Parse a rule and return it as generator. Each iteration yields tuples
    in the form ``(converter, arguments, variable)``. If the converter is
    `None` it's a static url part, otherwise it's a dynamic one.

    :internal:
    """
    pos = 0
    end = len(rule)
    do_match = _rule_re.match
    used_names = set()
    while pos < end:
        m = do_match(rule, pos)
        if m is None:
            break
        data = m.groupdict()
        if data['static']:
            yield None, None, data['static']
        variable = data['variable']
        converter = data['converter'] or 'default'
        if variable in used_names:
            raise ValueError('variable name %r used twice.' % variable)
        used_names.add(variable)
        yield converter, data['args'] or None, variable
        pos = m.end()
    if pos < end:
        remaining = rule[pos:]
        if '>' in remaining or '<' in remaining:
            raise ValueError('malformed url rule: %r' % rule)
        yield None, None, remaining

可以看到,flask讲一个URL Rule,首先拆解为 “/” 分隔的一个个单元。

之后,每个单元被解析为 converter(转换器), arguments(参数),variable(变量)。

以 /api/<int:id>/create 为例,可以知道得到三个单元

(None, None, "/api/"),
("int", None, "id"),
(None, None, "/create"),

第一个单元里,converter是None,则这个参数是一个URL中的静态字符串;

第二个单元内,converter是int,意即参数“id”是一个整型的变量;

第三个单元同第一个单元相同,不做多解释了。

通过以上分析,我们就拿到了Flask的Url Rule中变量的类型和名字,就可以做CLI自动生成中的参数解析了:)

PS:最近越来越赞同GongZi提的,“你会多少其实不重要要,重要的是你解决新问题的能力”,这种“Meta Learning”的能力,才是核心竞争力啊。

About:

以前自己单打独斗的时候,使用git主要是记录版本,很少用git来协作,协作也不过是两个人的小打小闹,一直在pull, 或者fetch merge,大家也都在修改master分支,没有明确的管理,进了新公司,需要比较严格的code review,主分支的管理都是确定的,这时候用rebase,reset,revert代替pull, fetch , merge之类的就好的多啦。

- 阅读剩余部分 -