0

1 か月分の日付のリストを作成しています。何が効率的か気になる

List<DateTime> GetDates(DateTime StartDay) {
  List<DateTime> dates = new List<DateTime>();
  int TotalDays=StartDay.AddMonths(1).AddDays(-1).Day;
  for (int i=1; i<TotalDays; i++) {
    dates.Add(new DateTime(StartDay.Year, StartDay.Month, i));
  }
  return dates;
}

また

List<DateTime> GetDates(DateTime StartDay) {
  List<DateTime> dates = new List<DateTime>();
  DateTime NextMonth = StartDay.AddMonths(1);
  for (DateTime curr=StartDay; !curr.Equals(NextMonth); curr=curr.AddDays(1)) {
    dates.Add(curr);
  }
  return dates;
}

基本的に、 new DateTime() または DateTime.addDays の方が効率的です。

アップデート:

static void Main(string[] args) {
  System.Diagnostics.Stopwatch sw=new System.Diagnostics.Stopwatch();
  long t1, t2, total;
  List<DateTime> l;
  DateTime begin = DateTime.Now;
  total = 0L;
  for (int i=0; i<10; i++) {
    sw.Start();
    l = GetDates(begin);
    sw.Stop();


    sw.Stop();
    t1 = sw.ElapsedTicks;
    sw.Reset();
    sw.Start();

    l = GetDates2(begin);
    sw.Stop();
    t2=sw.ElapsedTicks;
    total +=  t1- t2;

    Console.WriteLine("Test {0} : {1} {2} : {3}", i,t1,t2, t1- t2);
  }
  Console.WriteLine("Total: {0}", total);

  Console.WriteLine("\n\nDone");
  Console.ReadLine();
}

static List<DateTime> GetDates(DateTime StartDay) {
  List<DateTime> dates = new List<DateTime>();
  int TotalDays=StartDay.AddMonths(10000).AddDays(-1).Day;
  for (int i=1; i<TotalDays; i++) {
    dates.Add(new DateTime(StartDay.Year, StartDay.Month, i));
  }
  return dates;
}


static List<DateTime> GetDates2(DateTime StartDay) {
  List<DateTime> dates = new List<DateTime>();
  DateTime NextMonth = StartDay.AddMonths(10000);
  for (DateTime curr=StartDay; !curr.Equals(NextMonth); curr=curr.AddDays(1)) {
    dates.Add(curr);
  }
  return dates;
}
テスト 0: 2203229 63086205: -60882976
テスト 1: 63126483 102969090: -39842607
テスト 2 : 102991588 93487982 : 9503606
テスト 3: 93510942 69439034: 24071908
テスト 4 : 69465137 70660555 : -1195418
テスト 5 : 70695702 68224849 : 2470853
テスト 6 : 68248593 63555492 : 4693101
テスト 7 : 63578536 65086357 : -1507821
テスト 8: 65108190 64035573: 1072617
テスト 9 : 64066128 64933449 : -867321
合計: -62484058

終わり

結果は一貫して負です...かなり負であるため、コンストラクターと整数テストがより効率的な方法であるように見えます。

4

7 に答える 7

5

測定してください - テストプログラムを書いて、どれがより時間がかからないかを見てください。

于 2009-10-14T15:00:29.233 に答える
3

財務処理を行っていない限り、ここではパフォーマンスよりも読みやすさの方が気になります。それが証明されたボトルネックである場合にのみ、ここのようなどこかでパフォーマンスについて心配し始めてください。

于 2009-10-14T15:02:13.200 に答える
3

日時操作は新しい日時構造を返すと思うので、どちらの方法でも新しいインスタンスを作成します。

http://msdn.microsoft.com/en-us/library/system.datetime.aspx

于 2009-10-14T15:00:39.967 に答える
2

どちらも最終的に同じことを行うため、大きな違いはありません。

効率を求めている場合は、ティックを使用してください。すべての (私が見た) DateTime の呼び出しは、最終的には計算が完了する前にティックに変換されます。

于 2009-10-14T15:00:45.677 に答える
1

これが大きな違いを生むケースを想像するのは非常に困難ですが、Reflector はこのAddDays手法がより効率的であることを示しています。

AddDays(からAdd(Double, Int32))のコア ロジックを比較します。

long num = (long) ((value * scale) + ((value >= 0.0) ? 0.5 : -0.5));
if ((num <= -315537897600000L) || (num >= 0x11efae44cb400L)) {
    // Throw omitted
}
return this.AddTicks(num * 0x2710L);

DateTime(int, int, int)コンストラクターのコア ロジックへ (からDateToTicks):

if (((year >= 1) && (year <= 0x270f)) && ((month >= 1) && (month <= 12)))
{
    int[] numArray = IsLeapYear(year) ? DaysToMonth366 : DaysToMonth365;
    if ((day >= 1) && (day <= (numArray[month] - numArray[month - 1])))
    {
        int num = year - 1;
        int num2 = ((((((num * 0x16d) + (num / 4)) - (num / 100)) + (num / 400)) + numArray[month - 1]) + day) - 1;
        return (num2 * 0xc92a69c000L);
    }
}
// Throw omitted

AddDays指定された日数を同等のティック数 (long) に変換し、それを既存のティックに追加するだけです。

年/月/日のコンストラクターを使用して新しいを作成するにDateTimeは、さらに多くの計算が必要です。そのコンストラクターは、指定された年がうるう年かどうかを確認し、各月に日数の配列を割り当て、一連の追加操作を実行して、最終的にこれら 3 つの数値が表すティック数を取得する必要があります。


編集:DateTime.AddDays(int)よりも高速ですnew DateTime(int, int, int)が、最初のアルゴリズムは 2 番目のアルゴリズムよりも高速です。これはおそらく、2 番目のアルゴリズムでは反復コストがはるかに高いためです。編集で観察したように、これはDateTime.Equals整数を比較するよりもコストがかかるためである可能性があります。

于 2009-10-14T15:08:28.210 に答える
1

これは、実際に比較できるようにアルゴリズムが実装された、実際に動作するテスト プログラムです (ただし、まだ作業が必要です)。

 class Program
    {
        static void Main(string[] args)
        {
            IList<DateTime> l1, l2;
            DateTime begin = new DateTime(2000, 1, 1);

            Stopwatch timer1 = Stopwatch.StartNew();
            for (int i = 0; i < 10000; i++)
                l1 = GetDates(begin);
            timer1.Stop();

            Stopwatch timer2 = Stopwatch.StartNew();
            for (int i = 0; i < 10000; i++)
                l2 = GetDates2(begin);
            timer2.Stop();

            Console.WriteLine("new DateTime: {0}\n.AddDays: {1}",
                timer1.ElapsedTicks, timer2.ElapsedTicks);
            Console.ReadLine();
        }

        static IList<DateTime> GetDates(DateTime StartDay)
        {
            IList<DateTime> dates = new List<DateTime>();

            int TotalDays = DateTime.DaysInMonth(StartDay.Year, StartDay.Month);

            for (int i = 0; i < TotalDays; i++)
                dates.Add(new DateTime(StartDay.Year, StartDay.Month, i + 1));

            return dates;
        }


        static IList<DateTime> GetDates2(DateTime StartDay)
        {
            IList<DateTime> dates = new List<DateTime>();

            DateTime NextMonth = StartDay.AddMonths(1);

            for (DateTime curr = StartDay; !curr.Equals(NextMonth); curr = curr.AddDays(1))
                dates.Add(curr);

            return dates;
        }
    } // class

出力(コンマを追加しました):

新しい日時: 545,307,375
.AddDays: 180,071,512

これらの結果は私にはかなり明確に見えますが、正直なところ、もっと近いものになると思っていました.

于 2009-10-14T17:15:55.613 に答える
0

私はマークに同意します。両方の方法を自分でテストして、どちらが速いかを確認してください。Stopwatch クラスを使用して、各メソッドの実行にかかる正確な時間を取得します。私の最初の推測では、いずれにせよどちらも新しい構造を作成することになるため、速度の違いは無視できるものになるでしょう。また、1 か月分の日付 (最大 31 日) しか生成しないため、どちらの方法も他の方法よりもそれほど遅くなるとは思いません。おそらく、数千または数百万の日付を生成していたので、違いはありますが、31 の日付の場合、おそらく時期尚早の最適化です。

于 2009-10-14T15:06:36.133 に答える