web-dev-qa-db-fra.com

Comment chronométrer une opération en millisecondes en Ruby?

Je souhaite savoir combien de millisecondes une fonction particulière utilise. Je cherchais donc haut et bas, mais je ne pouvais pas trouver le moyen d’obtenir le temps en Ruby avec une précision milliseconde. 

Comment est-ce que tu fais ça? Dans la plupart des langages de programmation, c'est juste quelque chose comme

start = now.milliseconds
myfunction()
end = now.milliseconds
time = end - start
71
Earlz

Vous pouvez utiliser la classe Time de Ruby. Par exemple:

t1 = Time.now
# processing...
t2 = Time.now
delta = t2 - t1 # in seconds

Maintenant, delta est un objet float et vous pouvez obtenir un résultat aussi fin que le fournira la classe.

81
ezpz

Vous pouvez également utiliser la fonction intégrée Benchmark.measure:

require "benchmark"
puts(Benchmark.measure { sleep 0.5 })

Impressions:

0.000000   0.000000   0.000000 (  0.501134)
53
Simon Perepelitsa

L'utilisation de Time.now (qui renvoie l'heure de l'horloge murale) en tant que lignes de base pose quelques problèmes pouvant entraîner un comportement inattendu. Cela est dû au fait que l'heure murale est soumise à des modifications telles que l'insertion de secondes intercalaires ou le décalage temporel pour ajuster l'heure locale à une heure de référence.

S'il y a par exemple une seconde intercalaire insérée lors de la mesure, elle sera décalée d’une seconde. De même, en fonction des conditions du système local, vous devrez peut-être gérer l'heure avancée, des horloges plus rapides ou plus lentes ou même l'horloge qui saute dans le temps, ce qui entraîne une durée négative et bien d'autres problèmes.

Une solution à ce problème consiste à utiliser une horloge différente: une horloge monotone. Ce type d’horloge a des propriétés différentes de celles de l’horloge murale . Il s’incrémente monitonalement, c’est-à-dire qu’il ne remonte jamais et augmente à un taux constant. Avec cela, il ne représente pas l'horloge murale (c'est-à-dire l'heure à laquelle vous lisez une horloge sur votre mur), mais un horodatage que vous pouvez comparer à un horodatage ultérieur pour obtenir une différence.

En Ruby, vous pouvez utiliser un horodatage avec Process.clock_gettime(Process::CLOCK_MONOTONIC) comme suit:

t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
# => 63988.576809828

sleep 1.5 # do some work

t2 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
# => 63990.08359163

delta = t2 - t1
# => 1.5067818019961123
delta_in_milliseconds = delta * 1000
# => 1506.7818019961123

La méthode Process.clock_gettime renvoie un horodatage sous forme de float avec des fractions de secondes. Le nombre réel renvoyé n'a pas de signification définie (sur laquelle vous devriez compter). Cependant, vous pouvez être sûr que le prochain appel renverra un nombre plus grand et en comparant les valeurs, vous pourrez obtenir la différence de temps réel.

Ces attributs font de la méthode un candidat idéal pour mesurer les différences de temps sans voir votre programme échouer aux heures les moins opportunes (par exemple, à minuit le soir du Nouvel An lorsqu'une autre seconde intercalaire est insérée).

La constante Process::CLOCK_MONOTONIC utilisée ici est disponible sur tous les systèmes Linux, BSD et macOS modernes, ainsi que sur le sous-système Linux pour Windows. À ma connaissance, il n’est pas encore disponible pour les systèmes Windows "bruts". Là, vous pouvez utiliser l’appel GetTickCount au lieu de Process.clock_gettime, qui renvoie également une valeur de minuterie avec une granularité à la milliseconde sous Windows.

14
Holger Just

Vous devriez jeter un coup d'œil au module d'évaluation pour effectuer des analyses. Cependant, en tant que méthode de synchronisation rapide et sale, vous pouvez utiliser quelque chose comme ceci:

def time
  now = Time.now.to_f
  yield
  endd = Time.now.to_f
  endd - now
end

Notez l'utilisation de Time.now.to_f, qui contrairement à to_i, ne sera pas tronqué à quelques secondes.

13
sepp2k

Utilisez Time.now.to_f

1
sutch

La gemme absolute_time est un remplacement instantané de Benchmark, mais elle utilise des instructions natives pour être beaucoup plus précise.

1
Barry

Nous pouvons aussi créer une fonction simple pour enregistrer n’importe quel bloc de code:

def log_time
  start_at = Time.now

  yield if block_given?

  execution_time = (Time.now - start_at).round(2)
  puts "Execution time: #{execution_time}s"
end

log_time { sleep(2.545) } # Execution time: 2.55s
0
Slava Zharkov

J'ai un bijou qui peut profiler votre méthode Ruby (instance ou classe) - https://github.com/igorkasyanchuk/benchmark_methods .

Pas plus de code comme ça:

t = Time.now
user.calculate_report
puts Time.now - t

Maintenant vous pouvez faire:

benchmark :calculate_report # in class

Et appelez juste votre méthode

user.calculate_report
0
Igor Kasyanchuk

L'utilisation de Time.now.to_i renvoie la seconde passée du 1970/01 au 01/01. Sachant cela, tu peux le faire

date1 = Time.now.to_f
date2 = Time.now.to_f
diff = date2 - date1

Avec cela, vous aurez la différence en seconde magnitude. Si vous le souhaitez en millisecondes , ajoutez simplement le code

diff = diff * 1000
0
MARC.RS

Si tu utilises

date = Time.now.to_i

Vous obtenez du temps en secondes, ce qui est loin d’être précis, en particulier si vous synchronisez de petits morceaux de code.

0
user3401815