Вы можете указать порог и написать функцию, которая оценивает и устанавливает DateTime в соответствии с ним
var threshold = 15; //minutes
var dt = DateTime.Now.AddMinutes(-20);
//var dt = DateTime.Now;
DateTime resultDt;
DateTime thUp = dt.AddMinutes(15);
DateTime thDown = dt.AddMinutes(-15);
if (thUp.Hour != dt.Hour)
resultDt = new DateTime(dt.Year, dt.Month, dt.Day, thUp.Hour, 0, 0);
else if (thDown.Hour != dt.Hour)
resultDt = new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, 0, 0);
else
resultDt = dt;
Даже знайте, что Преждевременная оптимизация является корнем всего зла
{
local $\ = "\n";
print foreach @numbers;
}
но некоторые ожидания могут быть неправильными. Тест является немного странным, потому что произведенный может сделать некоторые странные побочные эффекты, и порядок может быть важным.
#!/usr/bin/env perl
use strict;
use warnings;
use Benchmark qw(:all :hireswallclock);
use constant Numbers => 10000;
my @numbers = (1 .. Numbers);
sub no_out (&) {
local *STDOUT;
open STDOUT, '>', '/dev/null';
my $result = shift()->();
close STDOUT;
return $result;
};
my %tests = (
loop1 => sub {
foreach my $current (@numbers) {
print "$current\n";
}
},
loop2 => sub {
foreach (@numbers) {
print "$_\n";
}
},
loop3 => sub {
local $\ = "\n";
print foreach @numbers;
}
);
sub permutations {
return [
map {
my $a = $_;
my @f = grep {$a ne $_} @_;
map { [$a, @$_] } @{ permutations( @f ) }
} @_
]
if @_;
return [[]];
}
foreach my $p ( @{ permutations( keys %tests ) } ) {
my $result = {
map {
$_ => no_out { sleep 1; countit( 2, $tests{$_} ) }
} @$p
};
cmpthese($result);
}
Можно ожидать, что loop2 должен быть быстрее, чем loop1
Rate loop2 loop1 loop3
loop2 322/s -- -2% -34%
loop1 328/s 2% -- -33%
loop3 486/s 51% 48% --
Rate loop2 loop1 loop3
loop2 322/s -- -0% -34%
loop1 323/s 0% -- -34%
loop3 486/s 51% 50% --
Rate loop2 loop1 loop3
loop2 323/s -- -0% -33%
loop1 324/s 0% -- -33%
loop3 484/s 50% 49% --
Rate loop2 loop1 loop3
loop2 317/s -- -3% -35%
loop1 328/s 3% -- -33%
loop3 488/s 54% 49% --
Rate loop2 loop1 loop3
loop2 323/s -- -2% -34%
loop1 329/s 2% -- -33%
loop3 489/s 51% 49% --
Rate loop2 loop1 loop3
loop2 325/s -- -1% -33%
loop1 329/s 1% -- -32%
loop3 488/s 50% 48% --
Иногда я последовательно наблюдал loop1
приблизительно на 15%-20% быстрее, чем loop2
но я не могу определить почему.
Я наблюдался сгенерированный байт-код для loop1 и loop2 и существует различие только один при создании my
переменная. Эта переменная внутренняя часть не выделяется и также не копируется таким образом, эта операция является очень дешевой. Различие прибывает, я думаю только от "$_\n"
создайте, который не является дешевым. Эти циклы должны быть очень похожими
for (@numbers) {
...
}
for my $a (@numbers) {
...
}
но этот цикл является более дорогим
for (@numbers) {
my $a = $_;
...
}
и также
print "$a\n";
является более дорогим, чем
print $a, "\n";
Вы определили, что существует проблема производительности в разделах кода, которые используют эти циклы? В противном случае Вы хотите пойти для того, который более читаем и таким образом более удобен в сопровождении. Любое различие в скорости, вероятно, будет незначительно, особенно по сравнению с другими частями Вашей системы. Всегда кодируйте для пригодности для обслуживания сначала, затем представляйте, затем кодируйте для производительности
"Преждевременная оптимизация является корнем всего зла" [1]
[1] Knuth, Donald. Структурное программирование с движением к Операторам, Журнал ACM, Вычисляя Обзоры, Vol 6, № 4, декабрь 1974. p.268.
Вы могли взглянуть на это учебное руководство, также существует глава, "Сравнивают Вашего Кода", Вы могли использовать для сравнения тех двух путей.
Сравнительный тест:
use Benchmark qw(timethese cmpthese);
my $iterations = 500000;
cmpthese( $iterations,
{
'Loop 1' => 'my @numbers = (1,3,5,7,9);
foreach my $current (@numbers)
{
print "$current\n";
}',
'Loop 2' => 'my @numbers = (1,3,5,7,9);
foreach (@numbers)
{
print "$_\n";
}'
}
);
Вывод:
Rate Loop 2 Loop 1
Loop 2 23375/s -- -1%
Loop 1 23546/s 1% --
Я выполнил его пару раз с переменными результатами. Я думаю смело можно сказать, что нет большой части различия.
Я не знаю, но... хорошо, в первую очередь, Вы сохраняете переменное присвоение во второй версии цикла. Я могу предположить, что, так как $ _ используется очень часто, он должен быть так или иначе оптимизирован. Вы могли попытаться представить его, очень хороший профилировщик Perl является NYTProf 2, записанным Tim Bunce.
Затем действительно достойно оптимизировать это мелочи? Я не думаю, что цикл будет иметь значение. Я предлагаю, чтобы Вы использовали профилировщика, чтобы измерить Ваш уровень и определить реальные узкие места. Обычно проблемы скорости расположены в 10% кода, который работает, 90% времени (возможно, не будет 10-90, но это - "известное" отношение :P).
Используя $_
идиома Perl, которая показывает закаленному программисту, что "текущий контекст" используется. Кроме того, много функций берут $_
по умолчанию как параметр, таким образом делая код более кратким.
Некоторые могли бы также просто спорить, это, "было трудно записать, должно быть трудно читать".
Я более интересующийся общим представлением использовать $ _ вместо печати...
Как примечание стороны, Лучшие практики Perl являются хорошим местом для движения в то, если Вы хотите начать учиться который идиомы избежать и почему. Я не соглашаюсь со всем, что он пишет, но он - пятно на большинстве раз.
Выполнение двух опций через " perl -MO = Concise, -terse, -src test.pl
", дает следующие два дерева операций:
для моего $ n (@num) {...}
LISTOP (0x9c08ea0) leave [1] OP (0x9bad5e8) enter # 5: my @num = 1..9; COP (0x9b89668) nextstate BINOP (0x9b86210) aassign [4] UNOP (0x9bacfa0) null [142] OP (0x9b905e0) pushmark UNOP (0x9bad5c8) rv2av SVOP (0x9bacf80) const [5] AV (0x9bd81b0) UNOP (0x9b895c0) null [142] OP (0x9bd95f8) pushmark OP (0x9b4b020) padav [1] # 6: for my $n (@num){ COP (0x9bd12a0) nextstate BINOP (0x9c08b48) leaveloop LOOP (0x9b1e820) enteriter [6] OP (0x9b1e808) null [3] UNOP (0x9bd1188) null [142] OP (0x9bb5ab0) pushmark OP (0x9b8c278) padav [1] UNOP (0x9bdc290) null LOGOP (0x9bdc2b0) and OP (0x9b1e458) iter LISTOP (0x9b859b8) lineseq # 7: say $n; COP (0x9be4f18) nextstate LISTOP (0x9b277c0) say OP (0x9c0edd0) pushmark OP (0x9bda658) padsv [6] # <=== OP (0x9b8a2f8) unstack
для (@num) {...}
LISTOP (0x8cdbea0) leave [1] OP (0x8c805e8) enter # 5: my @num = 1..9; COP (0x8c5c668) nextstate BINOP (0x8c59210) aassign [4] UNOP (0x8c7ffa0) null [142] OP (0x8ccc1f0) pushmark UNOP (0x8c805c8) rv2av SVOP (0x8c7ff80) const [7] AV (0x8cab1b0) UNOP (0x8c5c5c0) null [142] OP (0x8cac5f8) pushmark OP (0x8c5f278) padav [1] # 6: for (@num){ COP (0x8cb7f18) nextstate BINOP (0x8ce1de8) leaveloop LOOP (0x8bf1820) enteriter OP (0x8bf1458) null [3] UNOP (0x8caf2b0) null [142] OP (0x8bf1808) pushmark OP (0x8c88ab0) padav [1] PADOP (0x8ca4188) gv GV (0x8bd7810) *_ # <=== UNOP (0x8cdbb48) null LOGOP (0x8caf290) and OP (0x8ce1dd0) iter LISTOP (0x8c62aa8) lineseq # 7: say $_; COP (0x8cade88) nextstate LISTOP (0x8bf12d0) say OP (0x8cad658) pushmark UNOP (0x8c589b8) null [15] # <=== PADOP (0x8bfa7c0) gvsv GV (0x8bd7810) *_ # <=== OP (0x8bf9a10) unstack
Я добавил" <= ==
", чтобы обозначить различия между ними.
Если вы заметили, на самом деле больше операций для версии" для (@num) {...}
".
Так что, во всяком случае, версия « для (@num) {...}
», вероятно, медленнее, чем « для моей версии $ n (@num) {...}
».