@bhuztez 在 read/write 碰到 EWOULDBLOCK 的时候插 yield 进去,就不用手动写 yield 了
马克一下两个链接: http://golang.org/src/pkg/runtime/proc.c http://state-threads.sourceforge.net/docs/st.html
@reus goroutine 里大概也是在 read/write 里用长跳转把控制权交回调度器,相当于 yield 了吧?
#8 楼 @blacktulip 用了就是这样:
def qs x, *xs
l, r = xs.partition {|e| e <= x }
x ? [*qs(l), x, *qs(r)] : []
end
看外文资料,官方最新文档是捷径... 熟悉 unix/linux C 的话很多标准库的用法你一下就上手了,和很多 C 库都是一一对应的。例如 Date.strptime
和 man 3 strptime
的格式占位符是一样的。
web 搜索尽量加时间限定,不要被过时的内容坑了
事件框架的问题 1 是,破坏了对象的封装...
本来大家都是有主观能动性的,obj.write
现在变成了 obj.send_data
, 只是改了个名字本质没什么区别,obj.read
却变成了被动读 def obj.receive_data
. 两个对象只要相互收发数据,就得参照对方的实现去写。
问题 2 是,数据流不是自然按照写代码的顺序呈现出来,而是通过手动拼接回调接起来的。
这里不得不提下 Haskell ... Haskell 有专门的语法糖把这种回调套回调变成一个和顺序写法很相似的东西。例如一个 do-notation
f x = do
a <- g x
b <- h a
...
相当于翻译成用 >>=
串起来的样子
f x = return x >>= \x -> return (g x) >>= \a -> return (h a) >>= ...
而 >>=
虽然是个左结合的二元运算符,但坑爹的地方是 lambda 语法是能往右边延伸多长就多长的,其实 do-notation 每一行都是回调有木有...
f x = return x >>= (\x ->
return (g x) >>= (\a ->
return (h a) >>= ...
)
)
所以实际上这个丑陋的回调套回调,通过语法糖变成了优美的 do-notation...
不过 Fiber 走的是另一条路... 线程的特点是每线程都有自己的栈,读写共享数据的时候需要锁。而环保线程/Fiber 是 cooperative 的调度,自己在跑的时候就是老大,不用担心什么时候被人抢占,所以不用加锁,不用做全栈拷贝,只用在建立出分个叉就可以了。Fiber 的调度权在于自己 (Fiber.yield), 而不是 VM 或者计时器插一脚进来的。
Fiber 的用法举例:
f = Fiber.new{ i = 0; loop{ Fiber.yield i += 1 }}
f.resume #=> 1
f.resume #=> 2
既然 Fiber 可以暂停和重启,那么我们可以利用这个特性把 def obj.receive_data
改造成像 obj.read
一般人性友好的 API.
我们可以这么实现 read:
def read
while not eof
read_nonblock # 当然在 EM 里你就要对 receive_data 做点很搅脑的操作了...
Fiber.yield
end
end
client 对应的 EM::Connection
可以用 Fiber 包起来,当捕捉到事件的时候,就调用 fiber.resume
去继续操作。于是就实现了 em-synchrony.
# 例如歪了
我来说明下 EM 的原理吧
一个 blocking server 是长这个样子的:
# blocking loop, 没事干的时候会安静的 sleep
loop {
client = server.accept # 接受请求, 可以 ri accept 看看它的功效.
client.read # 其实 ruby 做了点处理, 和系统函数 read(blocking_fd) 不同, 只会塞住本线程
client.write
...
}
一个 nonblocking server 是长这样子的:
# busy loop, 没事干的时候还会吃 CPU 100%
loop {
# 把存着的 client 都跑一趟
client = server.try_accept # 伪码... 不过 kgio 里是有个 try_accept 的, 反正就是不塞住
client.read_nonblock # 不塞住, 所以就不一定成功...
client.write_nonblock
...
# 没跑完? 把 client 存起来
}
(以 linux 为例) 一个 event server 是长这样子的:
# event loop, 没事干的时候也很安静
loop {
event = epoll(timeout) # 当然也可以 poll 多个, 但这里就简简单单的 poll 一个
if event means server readable
client = server.accept
...
end
}
系统事件包括 fd (文件描述符) 可以读 (EPOLLIN), fd 可以写 (EPOLLOUT), 定时器跳跳,文件系统被改,信号...
系统提供了:
epoll_create
epoll_ctl
epoll
最后你写的服务器就变成 loop { epoll ; ...}
的样子
EM 做的事情,就是把上面 loop 中的 client 包装成 EM::Connection
对象,然后碰到 "fd 可读" 事件时,回调 Connection
对象的 receive_data
方法。
所以 EM.start 是长这样子的:
# 各种初始化后...
loop do
event = epoll(timeout)
conn = find or create connection by event
conn.receive_data(read_nonblock)
schedule thread # 触发线程调度和信号处理
end
multiplexing 没问题了,读也是非阻塞了,那写数据 send_data
是怎么处理的呢?
至此,EM 就产生了两个问题:
close_connection_after_writing
EM.next_tick{ ... }
还有一点,EM::Connection
对象除了来源于 server accept 以外,还可以来自 socket connect
鲍叔真是硅谷的开心果
抢占式调度有两种意思。一种意思是多个进程抢着 accept 同一个 file descriptor , 和 event loop 可以完全协同工作啊,nyara 的 production server 就是这样整的。另一种意思是人为的在字节码/机器码中隔三岔五的塞进类似于 yield point 的调度点 (例如 JVM 里有几十种迷你锁,锁和锁之间都是可调度的), 细到一定程度就出现了抢占的效果,多用于支持线程的虚拟机中,塞太多对于 web server 没什么好处,反而增加了 context switch 的开销... 塞少一点或者只塞到 EWOULDBLOCK 的时候,就和 event 类框架差不多了,再把控制权交给 OS, 就变成 event loop 了...
stackless 迷你线程的做法挺好的啊,不过为什么很多人都转用 gevent 了?
\1.3. iTerm 重启后能记住 iTerm tab 布局和颜色,但记不住目录。用 tmux 的话重启 iTerm 可以记住一个 iTerm tab 内各屏的上下文,但重启机器后还是记不住... 如果 tmux 的 tab 在 ssh 服务器上,那 tmux 也可以恢复会话,本地鸡怎么重启都没关系
\1. zsh 的配置 s host
产生绿色的 tab
# change tab color for ssh
tab-color() {
echo -ne "\033]6;1;bg;red;brightness;$1\a"
echo -ne "\033]6;1;bg;green;brightness;$2\a"
echo -ne "\033]6;1;bg;blue;brightness;$3\a"
}
tab-reset() {
echo -ne "\033]6;1;bg;*;default\a"
}
# Change the color of the tab when using SSH
# reset the color after the connection closes
s() {
if [[ -n "$ITERM_SESSION_ID" ]]; then
trap "tab-reset" INT EXIT
if [[ "$*" =~ "production|ec2-.*compute-1" ]]; then
tab-color 255 0 0
else
tab-color 0 255 0
fi
fi
ssh $*
}
compdef _ssh s=ssh
@wjch 400 行 java 你没有漏算 import
吧?还有页面 jsp (相信你不会把查数据库之类的放 jsp 里吧?), 还有各种 web.xml, pom.xml 配置文件...
#13 楼 @liker 把 turbolinks 去掉应该就好了 http://blog.steveklabnik.com/posts/2013-06-25-removing-turbolinks-from-rails-4
rspec 还是有点好处的
it "..."
测试的描述可以更清楚,而且不会因为意外方法重名而把前面的测试丢了
before :each
和 before :all
容易记住
可以选择 彩色输出 (-c), 文档输出 (-f d), 编辑器专用输出 (-f textmate), 还有 nyancat formatter...
should ==
把哪个是 expect, 哪个是 actual 分得很清楚,还可以少写一些括号 (assert_equal({}, output)
就不能省括号)
==
是最自然不会写错的,如果一段时间没写代码,就会忘记是该写 assert_equal
还是 assert_equals
了...
可以考虑搬到 thor 上...
windows 不能用 shotgun, 用这个:
注意那骗人的坐标轴,最低和最高差别只有 20% 左右 (可能还不到)
那这个能成功么?
echo foo | wkhtmltopdf --page-size Letter --margin-top 0.75in --margin-right 0.75in --margin-bottom 0.75in --margin-left 0.75in --encoding UTF-8 --print-media-type --quiet - - > a.pdf
改 Setting.upload_url
?
可能是没有 gem install wkhtmltopdf
如果装了,在命令行下面试试那个命令,看看错误信息是什么
要在 devkit 控制台下面安装
终于抢到沙发了...