The dawn of modern programmers

現代プログラマーの朝焼け

配列コピーのパフォーマンス比較

通常のエンタープライズアプリケーションではまずないことですが、現在配列の操作を多用しています。
その中でも配列のコピーをよく使用するのですがアルゴリズムで煮詰まってきたのでパフォーマンス検証を行いました。
検証した配列コピーの方法は以下の通りです。

  • Array.Copy() メソッドによる配列のコピー
  • for 文による配列のコピー
  • unsafe ステートメント内でのポインタによる配列のコピー

以下が検証で使用したコードです。

using System;
using System.Diagnostics;

namespace ArrayCopyPerformance
{
    class Program
    {
        static void Main(string[] args)
        {
            // 8KB
            int size = 1024 * 8;

            Console.WriteLine("TEST START...");

            MeasurePerformanceOfArrayCopyByMethod(size);
            MeasurePerformanceOfArrayCopyByForLoop(size);
            MeasurePerformanceOfArrayCopyByFixed(size);

            Console.WriteLine("TEST END.");
            Console.ReadLine();
        }

        static void MeasurePerformanceOfArrayCopyByMethod(int size)
        {
            byte[] source = new byte[size];
            byte[] dest = new byte[size];

            Stopwatch stopWatch = new Stopwatch();
            stopWatch.Start();

            Array.Copy(source, dest, size);

            stopWatch.Stop();

            Console.WriteLine("  BY 'Array.Copy' METHOD\t: TIME={0} ticks", stopWatch.ElapsedTicks);
        }

        static void MeasurePerformanceOfArrayCopyByForLoop(int size)
        {
            byte[] source = new byte[size];
            byte[] dest = new byte[size];

            Stopwatch stopWatch = new Stopwatch();
            stopWatch.Start();

            for (int i = 0; i < size; i++)
            {
                dest[i] = source[i];
            }

            stopWatch.Stop();

            Console.WriteLine("  BY 'for' LOOP STATEMENT\t: TIME={0} ticks", stopWatch.ElapsedTicks);

        }

        static unsafe void MeasurePerformanceOfArrayCopyByFixed(int size)
        {
            Stopwatch stopWatch = new Stopwatch();
            stopWatch.Start();

            fixed (byte* source = new byte[size])
            {
                fixed (byte* dest = new byte[size])
                {
                    byte* pSource = source;
                    byte* pDest = dest;
                    for (int i = 0; i < size; i++)
                    {
                        *pDest++ = *pSource++;
                    }
                }
            }

            stopWatch.Stop();

            Console.WriteLine("  BY 'fixed' UNSAFE STATEMENT\t: TIME={0} ticks", stopWatch.ElapsedTicks);
        }
    }
}

結果は以下の通り

TEST START...
BY 'Array.Copy' METHOD : TIME=16856 ticks
BY 'for' LOOP STATEMENT : TIME=120276 ticks
BY 'fixed' UNSAFE STATEMENT : TIME=191368 ticks
TEST END.

パフォーマンスを考慮しないといけない局面では「できるだけ Array.Copy() メソッドを使う」というソリューションが出ました。
Array.Copy() メソッドの処理が高速なのはランタイムに実装されたメソッドを使用しているためです。
(IL DASM で System.Runtime.ConstrainedExecution.ReliabilityContractAttribute が宣言されていることを確認しました。)

LINQ to SQL Beta 2 to RTM #1

RTMのインストールが完了したのでLINQ to SQL での変更点について確認した結果を記録しておきます。

詳細についてはMSDNで配布されている以下の資料を参照してください。
LINQ to SQL Beta 2 to RTM Breaking Changes

Table.Attach() メソッドで detach されていないエンティティを指定すると例外がスローされる

Beta 2 ではパスしていた以下のテストコードが RTM では エラー になりました。これは NotSupportedException がスローされるようになったためです。

[Test]
public void Attachで別のDataContextで取得したエンティティの変更をDBに送信できる()
{
    InsertTestCustomer();
    NorthwindDataContext otherContext = new NorthwindDataContext();
    Customer customer = otherContext.Customers.Single(c => c.CustomerID == "ARCWY");
    
    NorthwindDataContext context = new NorthwindDataContext();
    context.Customers.Attach(customer);
    customer.ContactName = "Osaka Office";
    Assert.That(customer, Is.SameAs(context.GetChangeSet().Updates[0]));
    context.SubmitChanges();
    DeleteTestCustomer();
}

というわけでまずはテストを修正して例外スローを確認します。

[Test]
[ExpectedException(typeof(NotSupportedException))]
public void トラキングが有効な状態で別のDataContextにAttachすると例外がスローされるべき()
{
    InsertTestCustomer();
    NorthwindDataContext otherContext = new NorthwindDataContext();
    Customer customer = otherContext.Customers.Single(c => c.CustomerID == "ARCWY");

    NorthwindDataContext context = new NorthwindDataContext();
    try
    {
        context.Customers.Attach(customer);
    }
    finally
    {
        DeleteTestCustomer();
    }
}

次に Attach が成功するテストを考えましたがこれが問題です。
dettach ってなんやねん?です。
Table.Detach() メソッドはないし、Dispose も null 代入もダメでした。
苦肉の策が DataContext.ObjectTrackingEnabled を false に指定する方法です。

テストコードは以下のようになります。

[Test]
public void トラッキングを無効にすればAttachで別のDataContextで取得したエンティティの変更をDBに送信できる()
{
    InsertTestCustomer();
    NorthwindDataContext otherContext = new NorthwindDataContext() { ObjectTrackingEnabled = false };
    Customer customer = otherContext.Customers.Single(c => c.CustomerID == "ARCWY");
      
    NorthwindDataContext context = new NorthwindDataContext();
    context_.Customers.Attach(customer);
    customer.ContactName = "Osaka Office";
    Assert.That(customer, Is.SameAs(context.GetChangeSet().Updates[0]));
    context.SubmitChanges();
    DeleteTestCustomer();
}

SQL Server Profiler で確認した実行SQLの結果は以下の通りです。
無事に更新も実行できています。

exec sp_executesql N'UPDATE [dbo].[Customers]
SET [ContactName] = @p2
WHERE ([CustomerID] = @p0) AND ([CompanyName] = @p1) AND ([ContactName] IS NULL) AND ([ContactTitle] IS NULL) AND ([Address] IS NULL) AND ([City] IS NULL) AND ([Region] IS NULL) AND ([PostalCode] IS NULL) AND ([Country] IS NULL) AND ([Phone] IS NULL) AND ([Fax] IS NULL)',N'@p0 nchar(5),@p1 nvarchar(12),@p2 nvarchar(12)',@p0=N'ARCWY',@p1=N'Archway Inc.',@p2=N'Osaka Office'

未だ dettach について理解できていないのでもうしばらく調査が必要です。

ただ、N層アプリケーションでAttachを使用する局面では更新元データは基本トラッキングをオフにしておくのもよいかと考えています。(当然オフにした方がパフォーマンスがよいので)

Visual Studio 2008 Beta2 to RTM 移行の注意点

ScottGu's Blog でも掲載されていますが、VS 2005 との共存環境で実際に移行したので注意点を書いておきます。
ハマるポイントが抜けていたので修正しました。

VS 2008 Beta2 のアンインストール

まずはVSのセットアップメニューからアンインストールすします。

Visual Studio 2008 のアンインストール中に「以下のプロセスを終了して下さい。」というダイアログが表示される場合がありますが、
必ず「無視」( Ignore ) を選択してください。「再試行」 ( Retry ) を選択するとアンインストールが停止してしまいます。

アンインストールが成功しても残念ながら完全に削除されずに以下の機能が残ってしまいます。

これらの機能はコントロールパネルのプログラムと機能からアンインストールする必要があります。

VS 2005 の修復インストール

VS 2005 との共存環境の場合、VS 2008 をアンインストールすると、VS 2005 に影響が出る場合があるためセットアップから修復インストールを実行する必要があります。

ここでも「以下のプロセスを終了して下さい。」というダイアログが表示される場合がありますが、
必ず「無視」( Ignore ) を選択してください。「再試行」 ( Retry ) を選択するとアンインストールが停止してしまいます。

VS 2008 RTM のインストール

Beta2 のアンインストール後ですが、以下の作業が必要です。

  1. 再起動
    • # 事前に再起動してから実行したのでこの点については未確認です。
  2. Windows Update の確認
    • VS 2008 ( .NET Framework 3.5 ) のインストール中に Windows Update が実行されるとセットアップがフリーズしてしまいます。

上記の作業後に VS 2008 のセットアップを開始すれば無事にインストールが完了します。

Archway Developers Night 第1回 開催

日頃私たちが行っている研究開発の結果を皆さんにフィードバックしたいと、弊社主催で勉強会を開催します。
興味がある方は是非ご参加ください。

登録と詳細の確認はこちらです。

Archway Developers Night 第1回
.NET開発者のためのテスト駆動開発入門
テスト駆動開発とはプログラマのための設計手法〜

開催概要

テスト駆動開発(Test Driven Development)は、その名前から単なる「テスト技法」であるという誤った理解がされがちです。
この勉強会でデベロッパーのための「設計手法」というテスト駆動開発に対する真の理解を得てみませんか。
今回はオープンソースの.NET用テスティングフレームワークであるNUnitを使用して、ワークショップ形式でテスト駆動開発を体験して頂きます。
このワークショップで使用する開発言語はC#が対象となっています。特にテスト駆動開発に関する前提知識はなくても問題ありませんので、どうぞお気軽にご参加下さい。

日時

2007年12月11日(火) 18:00〜21:00(受付開始 17:30)

会場

市ヶ谷健保会館会議室

東京都新宿区市谷仲之町4-39
Tel 03-3225-1133 Fax 03-3354-6726
●都営新宿線曙橋駅下車徒歩6分
●都営大江戸線牛込柳町駅下車徒歩8分
 (牛込柳町駅東口より外苑東通りに出てください)
●地下鉄丸ノ内線四谷三丁目駅下車徒歩15分

aiNote Beta3 (2007年9月版) リリース

弊社で開発中のマインドマップ機能を搭載したソフトウェアファクトリ(ソフトウェア開発を自動化するための取り組み)支援ツールであるaiNoteの最新版がリリースされました。

私自身もヘビーユーザーですが非常に使いやすいツールとなっていますので、まだ使用されたことのない方は是非インストールしてみてください。

旧バージョン (ベータ3 2007年3月版) は 2007/10/1 をもって動作しなくなりますので、
現在ご利用中の方はアップデートをお願い致します。

ダウンロードは以下からです。
http://www.archway.co.jp/Home/aiNote.aspx

リフレクションでオブジェクトのDeep Copy

制約はあるけど簡単なValueObjectであればこれでDeepcopyできたり。
使いすぎるとパフォーマンスに影響出ますね。

using System;
using System.Reflection;

namespace HogeHoge
{
    public class CloneGenerator
    {

        public static T Clone<T>(T target) where T: new()
        {
            T clone = new T();
            FieldInfo[] fields = target.GetType().GetFields(
                BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
            foreach (FieldInfo field in fields)
            {
                field.SetValue(clone, field.GetValue(target));
            }
            
            return clone;
        }

    }
}

ASP.NETの認証 #1

技術検証の機会があったのだが、理解の足りないことばかりだったのでログを残すことに。

まずはフォーム認証から書いていこう。

#それにしても.NETは標準(MSが想定する)実装をはずれると坂道を転がるように面倒になるなぁ。