Hatena::ブログ(Diary)

はむ日記

2011-12-23

Visual Studio 2010でアプリケーションのパフォーマンス・チューニング

DBアプリケーションのパフォーマンス・チューニング − @ITの内容メモ

クエリのデータ転送量を減らす

不要な項目をSELECT区に含めない。安易に*を使用しない。

SQLServerからの転送量がかなり節約できる。


クエリの内容をデバッグ出力

Entity Frameworkでは、ObjectQueryクラスのToTraceStringメソッドを使用する。

var q = from a in db.Tweets select a;
var trace = ((System.Data.Objects.ObjectQuery)q).ToTraceString();

ObjectQuery(T) クラス (System.Data.Objects)


大量のデータをインポートする方法

テストデータを作成して、それをテーブルにInsertする場合、現実的には2方法が考えられる。

    1. ManagementStudioのオブジェクトエクスプローラから対象テーブルを右クリックし、「上位200行の編集」を選択。編集可能状態でテーブルデータが表示されるので追加データを貼り付ける。
    2. 「データのインポートおよびエクスポートウィザードを使用してデータをインポートする。

普段は手軽なので1方法でインポートしているが、速度が遅いので大量データをインポートする必要がある場合は、2方法を利用すべき。

2011-12-18

こんまり式の片付け

テレビで見て感心したので頭に残っていることを書き出しておく。

種類別に片付け

場所ごとに片付けするのではなく、種類ごと(服,本,書類,,,)に片付ける。

整理対象種類のものを一箇所にまとめて片付けする。こうすることでものの量が把握できる。(その多さにびっくりして片付けないと!となる?)

片付けの順番

絶対厳守

    1. 衣類
    2. 書類
    3. 小物
    4. 思い出の品(写真,記念品,,,)

衣類の整理

「部屋着にします」は禁句。

不要なぬいぐるみは、目隠しして捨てる。供養する気持ちで送り出すこと。

小物

不要なコード類(テレビやビデオの線)は原則捨てる。

説明できないものは捨てる。

思い出の品

捨てられないからと言って、実家送りは厳禁。実家を思い出の墓場にしては行けない。

不用品はどこに行っても不要品。



人生がときめく片づけの魔法

人生がときめく片づけの魔法

2011-12-16

レバレッジ・リーディング

読書は自身への投資となる。

本で得た知識を仕事や生活で活かすことで大きなリターンを得ることができる。

"読書"ではなく、自分を運用するための投資作業という意味合い(-> レバレッジリーディング)。

多読を行い、より重要な知識を仕入れる。

同じジャンルの様々な本を読み、内容で被っているところは「普遍的かつ重要な事柄」といえる。

様々な著者の意見や経験を知ることができるので、一辺倒にならない。

目的設定

ただ読むだけではダメ。はじめに、本を読む具体的な目的を設ける。

読書に制限時間を設ける。

だらだら読書しても頭に入らないので、制限時間を設ける。

本文の前に読む

帯・まえがき・目次・著者プロフィールから、おおよその内容が見えてくる。まえがきでそそられなかたらそれはつまらない本。

購入する前に確認すべし。

すべて読まない

多読を行うので、すべて読む時間はない。一語一句読むのではなく、流し読みする。

目的設定がしっかりと行われていると、カラーバス効果によって、重要キーワードが浮き上がってくるはず。その周辺をしっかりと読む。*1

"むだな箇所もしっかり読んで、時間を無駄にするよりは重要なところだけをしっかり頭にいれたほうが効率が良い。"という考え方。

読書後のアフターケア

内容の概要をまとめる。(ノート・書籍に書き込み・ブログにアップ)これを継続して何度も目を通し、体に染み込ませる。こうすることで自然と実践で使えるようになる。



目的設定やすべて読まないという手法は読書にとどまらず様々適用できると思う。

("摘み食い"なので、上辺だけの知識にならなように気を付けないと。必要に応じて深く潜ることも行うべき。)


レバレッジ・リーディング

レバレッジ・リーディング

2011-12-10

IObservable<T>インターフェイス

IObservable(T) インターフェイス?(System)

IObserver(T) インターフェイス?(System)

.NET Framework 4から追加されたこれらのインターフェイスを使ったサンプルを作成していました。

オブザーバーパターンは一方通行の通知を行うパターンだというのに、チャットアプリケーションを作ってしまったため

クライアントウィンドウがごちゃごちゃしています。



配信側、受信側クラス

public class ChatHost : IObservable<ChatMessage>
{
    protected List<IObserver<ChatMessage>> observers = new List<IObserver<ChatMessage>>();

    public ChatHost()
    {
    }

    public IDisposable Subscribe(IObserver<ChatMessage> observer)
    {
        observers.Add(observer);
        return new _ChatMessage(this, observer);
    }

    private class _ChatMessage : IDisposable
    {
        private ChatHost parent;
        private IObserver<ChatMessage> me;

        public _ChatMessage(ChatHost parent, IObserver<ChatMessage> me)
        {
            this.parent = parent;
            this.me = me;
        }

        public void Dispose()
        {
            if (parent != null && parent.observers.Contains(me))
                parent.observers.Remove(me);
        }
    }

    public void AddMessage(ChatMessage msg)
    {
        if (msg == null)
        {
            foreach (var o in observers)
            {
                o.OnError(new ChatException()
                {
                    Msg = new ChatMessage()
                    {
                        From = "SYSTEM",
                        Message = "無言メッセージが送信されました。送ったのは誰だ!!",
                        SendAt = DateTime.Now
                    }
                });
            }
            return;
        }

        foreach (var o in observers)
        {
            o.OnNext(msg);
        }
    }

    public void EndChat()
    {
        foreach (var o in observers)
        {
            o.OnNext(new ChatMessage()
            {
                From = "SYSTEM",
                Message = "今日はお開きです!!",
                SendAt = DateTime.Now
            });
        }

        int obsCount = observers.Count;
        for (int i = obsCount - 1; i >= 0; i--)
        {
            observers[i].OnCompleted();
        }
    }
}

public class ChatException : Exception
{
    public ChatMessage Msg
    {
        get;
        set;
    }

    public ChatException()
        : base()
    {
    }
}


public class ChatClient : IObserver<ChatMessage>
{
    private IDisposable unsubscriber;
    private ObservableCollection<ChatMessage> msgItemList;

    public ChatClient(ObservableCollection<ChatMessage> msgItemList)
    {
        this.msgItemList = msgItemList;
    }

    public virtual void Subscribe(IObservable<ChatMessage> provider)
    {
        if (provider != null)
            unsubscriber = provider.Subscribe(this);
    }

    public void OnCompleted()
    {
        if(unsubscriber != null)
            unsubscriber.Dispose();
    }

    public void OnError(Exception error)
    {
        var charError = error as ChatException;
        if (charError == null)
            return;

        msgItemList.Add(charError.Msg);
    }

    public void OnNext(ChatMessage value)
    {
        msgItemList.Add(new ChatMessage()
        {
            From = value.From,
            Message = value.Message,
            SendAt = value.SendAt
        });
    }
}

メインウィンドウ。クライアント画面表示やチャットセッションの切断をおこなう。

<Window x:Class="ObservableSample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <Button x:Name="btnAddClient" Click="btnAddClient_Click" Margin="10">クライアント追加</Button>
        <Button x:Name="btnEnd" Margin="10" Click="btnEnd_Click">終了</Button>
    </StackPanel>
</Window>
public partial class MainWindow : Window
{
    private ChatHost provider = new ChatHost();

    public MainWindow()
    {
        InitializeComponent();
    }

    private void btnAddClient_Click(object sender, RoutedEventArgs e)
    {
        var window = new Window1(provider);
        window.Show();
    }

    private void btnEnd_Click(object sender, RoutedEventArgs e)
    {
        provider.EndChat();
    }
}

クライアントウィンドウ。

<Window x:Class="ObservableSample.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="356" Width="518" Loaded="Window_Loaded" Closed="Window_Closed">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="8*" />
            <RowDefinition Height="2*" />
        </Grid.RowDefinitions>
        
        <ListView Grid.Row="0" x:Name="listview1">
            <ListView.View>
                <GridView>
                    <GridViewColumn DisplayMemberBinding="{Binding Path=From}" Header="送信者" Width="100" />
                    <GridViewColumn DisplayMemberBinding="{Binding Path=Message}" Header="メッセージ" Width="150" />
                    <GridViewColumn DisplayMemberBinding="{Binding Path=SendAt}" Header="日付" Width="200" />
                </GridView>
            </ListView.View>
        </ListView>

        <StackPanel Orientation="Horizontal" Grid.Row="1">
            <TextBox x:Name="textbox1" Width="300" Margin="5"></TextBox>
            <Button x:Name="button1" Width="100" Margin="5" Click="button1_Click">送信</Button>
        </StackPanel>
    </Grid>
</Window>
public partial class Window1 : Window
{
    private ObservableCollection<ChatMessage> msgs = new ObservableCollection<ChatMessage>();
    private ChatHost provider;
    private ChatClient observer;
    private string userName = "";

    public Window1()
    {
        InitializeComponent();
    }

    public Window1(ChatHost provider)
    {
        this.provider = provider;
        this.observer = new ChatClient(msgs);
        observer.Subscribe(provider);

        InitializeComponent();
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        listview1.ItemsSource = msgs;

        //ユーザー名入力ダイアログを表示、ユーザー名設定。
        var dialog = new Window2();
        dialog.Owner = this;
        dialog.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterOwner;
        dialog.ShowInTaskbar = false;
        dialog.ShowDialog();
        this.userName = dialog.UserName;
        this.Title = userName;
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        if (textbox1.Text.Trim().Length == 0)
        {
            provider.AddMessage(null);
        }
        else
        {
            provider.AddMessage(new ChatMessage()
            {
                From = userName,
                Message = textbox1.Text,
                SendAt = DateTime.Now
            });
        }
    }

    private void Window_Closed(object sender, EventArgs e)
    {
        observer.OnCompleted();
    }
}

2011-11-29

匿名メソッドの変数キャプチャ

基本的な大事なことです。

Javascriptクロージャと同じ考え方です。。。

ど忘れしてましたので再確認を兼ねて書き置きします。


//非同期でFriendGridにイメージを追加していく  (ダメバージョン)
Task.Factory.StartNew(() => {
    foreach (var friend in ViewModel.Friends)
    {
        //ループで一意な変数がキャプチャされるので、全て末尾要素が選択されてしまう。
        Dispatcher.BeginInvoke(new Action(() => {
                FriendGrid.Children.Add(new Image(){DataContext = friend}); 
            })
            , System.Windows.Threading.DispatcherPriority.Background, null
        );
    }
}); 

//非同期でFriendGridにイメージを追加していく  (OKバージョン)
Task.Factory.StartNew(() => {
    foreach (var friend in ViewModel.Friends)
    {
        var f = friend;  //ループ内にローカル変数を追加。匿名メソッドがこの変数をキャプチャするようにする。
        Dispatcher.BeginInvoke(new Action(() => {
                FriendGrid.Children.Add(new Image(){DataContext = f}); 
            })
            , System.Windows.Threading.DispatcherPriority.Background, null
        );
    }
}); 

参考

第5回 匿名メソッドとデリゲート − @IT