use*_*951 7 ruby python performance fork
我看到了问题为什么Process.fork在OS X上的Ruby中变慢了?并能够确定Process.fork
并没有真正做任务,一般情况下,速度较慢.
但是,它似乎确实Time.utc
特别慢了.
require 'benchmark'
def do_stuff
50000.times { Time.utc(2016) }
end
puts "main: #{Benchmark.measure { do_stuff }}"
Process.fork do
puts "fork: #{Benchmark.measure { do_stuff }}"
end
Run Code Online (Sandbox Code Playgroud)
以下是一些结果:
main: 0.100000 0.000000 0.100000 ( 0.103762)
fork: 0.530000 3.210000 3.740000 ( 3.765203)
main: 0.100000 0.000000 0.100000 ( 0.104218)
fork: 0.540000 3.280000 3.820000 ( 3.858817)
main: 0.100000 0.000000 0.100000 ( 0.102956)
fork: 0.520000 3.280000 3.800000 ( 3.831084)
Run Code Online (Sandbox Code Playgroud)
一个线索可能是上面发生在OS X上,而在Ubuntu上,似乎没有区别:
main: 0.100000 0.070000 0.170000 ( 0.166505)
fork: 0.090000 0.070000 0.160000 ( 0.169578)
main: 0.090000 0.080000 0.170000 ( 0.167889)
fork: 0.100000 0.060000 0.160000 ( 0.169160)
main: 0.100000 0.070000 0.170000 ( 0.170839)
fork: 0.100000 0.070000 0.170000 ( 0.176146)
Run Code Online (Sandbox Code Playgroud)
任何人都可以解释这种奇怪吗?
进一步的调查:
@tadman建议它可能是macOS/OS X时间码中的一个错误,所以我在Python中编写了一个类似的测试:
from timeit import timeit
from os import fork
print timeit("datetime.datetime.utcnow()", setup="import datetime")
if fork() == 0:
print timeit("datetime.datetime.utcnow()", setup="import datetime")
else:
pass
Run Code Online (Sandbox Code Playgroud)
同样,在Ubuntu上,forked/main进程的基准是相同的.但是,在OS X上,分叉进程现在比主进程略快,这与 Ruby中的行为相反.
这让我相信"fork惩罚"的来源是在Ruby实现中,而不是在OS X时间实现中.
事实证明,在函数中time.c
,减速是由于与函数中的两个函数调用大致相等gmtime_with_leapsecond
.这两个功能是tzset
和localtime_r
.
这个发现让我想到了为什么在Mac OS X上分叉后tzset()的速度慢了很多?其中当前的问题可以合理地说是重复的.
那里有两个答案,既没有被接受,也指出了涉及其中任何一个的根本原因
tzset
和localtime
/ localtime_r
,或的"异步信号安全"fork
d 时无效.事实上,减速只发生在几年没有已知的闰秒(由用户发现其他人发现)显然是因为gmtime_with_leapsecond
当Ruby 知道年份没有闰秒时,Ruby不会调用.
我不确定为什么Python中没有这种减速.一种可能的解释是我的测试脚本使用fork
并且utcnow
可能没有创建调用tzset
或localtime
/ 的子进程localtime_r
.