为什么在OS X上的Ruby中(而不是在Python中),Time.utc在分支过程中变慢? [英] Why is Time.utc slower in a forked process in Ruby on OS X (and not in Python)?

查看:90
本文介绍了为什么在OS X上的Ruby中(而不是在Python中),Time.utc在分支过程中变慢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看到了一个问题为什么可以使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中的两个函数调用大致相等.这两个功能是tzsetlocaltime_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

  • tzsetlocaltime/localtime_r的异步信号安全"状态,或
  • Apple使用被动通知注册表,该注册表在fork之后失效.
  • the "async-signal-safe"-ness of tzset and localtime/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中没有这样的速度下降.一种可能的解释是,我使用forkutcnow的测试脚本可能没有创建调用tzsetlocaltime/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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆