为什么在OS X上的Ruby中(而不是在Python中),Time.utc在分支过程中变慢? [英] Why is Time.utc slower in a forked process in Ruby on OS X (and not in Python)?
问题描述
我看到了一个问题为什么可以使Process.fork在OS X上的Ruby中使工作变慢吗?并能够确定Process.fork
不会 实际上使任务变慢.
I saw the question Why does Process.fork make stuff slower in Ruby on OS X? and was able to determine that Process.fork
does not actually make tasks, in general, slower.
但是,它似乎确实使Time.utc
特别慢.
However, it does seem to make Time.utc
, in particular, much slower.
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
以下是一些结果:
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)
一个线索可能是上述情况发生在OS X上,而在Ubuntu上似乎没有什么不同:
One clue might be that the above takes place on OS X, whereas on Ubuntu, there doesn't seem to be a difference:
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)
有人能解释这种奇怪吗?
Can anyone explain this oddity?
进一步调查:
@tadman 建议这可能是macOS/OS X时间码中的错误,所以我写了类似的文章在Python中测试:
@tadman suggested that it might be a bug in the macOS / OS X time code, so I wrote a similar test in 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
同样,在Ubuntu上,分叉/主进程的基准相同.但是,在OS X上,分叉的进程现在比主进程(在Ruby中的行为的相反)要快更快.
Again, on Ubuntu, the benchmarks are the same for the forked/main processes. On OS X, however, the forked process is now slightly faster than the main process, which is the opposite of the behavior in Ruby.
这使我相信前叉惩罚"的来源是在Ruby实现中,而不是在OS X time实现中.
This leads me to believe that the source of the "fork penalty" is in the Ruby implementation and not in the OS X time implementation.
推荐答案
事实证明,速度下降的原因与功能gmtime_with_leapsecond
中的time.c
中的两个函数调用大致相等.这两个功能是tzset
和localtime_r
.
As it turns out, the slowdown is due in approximately equal measure to two function calls in time.c
, in the function gmtime_with_leapsecond
. The two functions are tzset
and localtime_r
.
That discovery led me to the question Why is tzset() a lot slower after forking on Mac OS X?, of which the current question might reasonably be said to be a duplicate.
那里有两个答案,两个都没有被接受,这表明涉及其中一个的根本原因
There are two answers there, neither accepted, which point to root causes involving either
-
tzset
和localtime
/localtime_r
的异步信号安全"状态,或 - Apple使用被动通知注册表,该注册表在
fork
之后失效.
- the "async-signal-safe"-ness of
tzset
andlocaltime
/localtime_r
, or - Apple's use of a passive notification registry that invalidates when
fork
'd.
减速仅在几年内发生,而没有已知的leap秒这一事实(由用户那个其他人)显然是由于Ruby在知道年份没有leap秒时不调用gmtime_with_leapsecond
的事实.
The fact that the slowdown only occurs in years with no known leap seconds (as discovered by user that other guy) is obviously due to the fact that Ruby doesn't call gmtime_with_leapsecond
when it knows that the year has no leap seconds.
我不确定为什么Python中没有这样的速度下降.一种可能的解释是,我使用fork
和utcnow
的测试脚本可能没有创建调用tzset
或localtime
/localtime_r
的子进程.
I'm not sure why there is no such slowdown in Python. One possible explanation is that my test script using fork
and utcnow
may not be creating a child process that calls tzset
or localtime
/localtime_r
.
这篇关于为什么在OS X上的Ruby中(而不是在Python中),Time.utc在分支过程中变慢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!