MySQLでHDD/SSDのアクセススピードを比較する

SSDにするとBlukcopyは5倍ぐらい早くなる – Moonmile Solutions Blog の比較として、MySQL では、SSD/HDD はどうなんだろうね?という話です。MySQL の Connector には Bulkcopy っぽいものがないので、ちまちまと insert しています。なので、その分遅くなるので、適当に1000件単位でトランザクション使って commit します。1件ずつ insert するよりは早いのですが、SQL Server よりは SSD 比で 10 倍ぐらい、HDD 比で 2 倍ぐらい遅いです。SSD/HDD で倍数に差がでているのは、SQL Server + SSD がむちゃくちゃ早いからですね。

追記 MySqlBulkLoader というものがあるそうなので、後で試します。

imageimage

imageimage

SSD で 65.3秒、HDD で 74.2秒。

SSD HDD
SQL Server 7.8 sec 32.1 sec
MySQL 65.3 sec 74.2 sec

ってことで、SQL Server は bulkcopy, MySQL はトランザクション使ったinsert文なので、相互には比較できませんが(今度 SQL Server のほうを insert 文に変えて実験しましょう)、SSDとHDDの比較で言えば、SQL Server のほうが断然効果的…という結論ではなくて、MySQL が SSD の書き込みスピードに追い付いていないってのが遅い原因です。

書き込み速度 SSD HDD
SQL Server 132 MB/sec 35.1 MB/sec
MySQL 11.0 MB/sec 約7 MB/sec

になるので、SQL Server の HDD 書き込みよりも遅いスピードで SSD に書きにいっちゃってます。この要因は、プログラム側にもあって、

  • MySQLにバルクコピーがないので、ちまちま insert してる。
  • たぶん、DataTable から CommandParamter に移す時にスピードが遅くなってる。

てな感じでしょうか。でも、まあ、100万件のアクセス生ログを 1分弱で insert できるのは結構よいかなと。以前、mysqldump したのだと30分位かかって気がします(以前とは、メモリもCPUも違うので単純比較はできませんが)。

MySQL のデータファイルを HDD/SSD に振り分ける方法は、漢(オトコ)のコンピュータ道: InnoDBのファイルサイズ管理 にある、innodb_file_per_table の設定と、シンボリックリンク(mklink)を使っています。この方法は別のエントリにまとめます。

以下は、insert 文のところの抜粋です。参考にでも。

async Task GoBlukCopy(string CNSTR)
{
    MySqlConnection cn = new MySqlConnection(CNSTR);
    MySqlCommand cmd = new MySqlCommand("INSERT INTO logs  values ( @dt, @code, @ip, @req, @url )", cn );
    cmd.Parameters.Add(  new MySqlParameter("@dt",  MySqlDbType.String ));
    cmd.Parameters.Add(  new MySqlParameter("@code",  MySqlDbType.String ));
    cmd.Parameters.Add(  new MySqlParameter("@ip",  MySqlDbType.String ));
    cmd.Parameters.Add(  new MySqlParameter("@req",  MySqlDbType.String ));
    cmd.Parameters.Add(  new MySqlParameter("@url",  MySqlDbType.String ));

    DateTime start = DateTime.Now;

    _completed = false;
    _count = 0;
    await Task.Factory.StartNew(
        () =>
        {
            cn.Open();

            // 1000件ごとにcommit する
            MySqlTransaction tr = cn.BeginTransaction();
            foreach (DataRow row in _dt.Rows)
            {
                cmd.Parameters["@dt"].Value = row["dt"];
                cmd.Parameters["@code"].Value = row["code"];
                cmd.Parameters["@ip"].Value = row["ip"];
                cmd.Parameters["@req"].Value = row["req"];
                cmd.Parameters["@url"].Value = row["url"];
                cmd.ExecuteNonQuery();
                _count++;
                if (_count % 1000 == 0)
                {
                    tr.Commit();
                    tr = cn.BeginTransaction();
                }
            }
            tr.Commit();
            cn.Clone();
            _completed = true;
        });
}
カテゴリー: MySQL, パフォーマンス | MySQLでHDD/SSDのアクセススピードを比較する はコメントを受け付けていません

SQL Server のデータベースファイルを SSD に移す

SQL Server のファイルは、別の HDD/SSD に置くことができます。ってことで、基本技なのですが、メモ的に書いておきます。

■SQL Server Management Studio で新しいデータベースを作る

新しいデータベースを作ると、初期値が「C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQLDATA」になっています。

image

「MSSQL11.MSSQLSERVER」なところは、SQL Serverのバージョンとかインスタンスとかで決められているので、バックアップを取りたいときはここから直でコピーしてもOK。まあ、「タスク」→「バックアップ」でバックアップするのが筋なんですが。

■データベースファイルをSSDに移動させる。

移動させる、というかデータベースを作成するときに別のドライブにファイルを作ります。

image

私のPCは、CドライブがSSDなので、これはわざと E ドライブにデータベースファイルを作っています。SSDにするとBlukcopyは5倍ぐらい早くなる – Moonmile Solutions Blog の計測用ですね。

データベースファイルを他のドライブに作るのは、いくつか利点があって、

  • Cドライブが忙しい時(テンポラリキャッシュアクセスなど)にも DB アクセスが遅くならない。
  • Cドライブがクラッシュした時でもデータが生き残る。
  • ドライブ毎、他のPCに持っていける?(アクセス権限を修正しないとといけないかも)
  • Cドライブの容量を圧迫しない(SSD化で容量が小さいときとか)

というものがあります。特に、最初の利点は大きくて、プログラムのほうで何かがりがりやりながら、DB に insert アクセスということをやると C ドライブだけだと HDD の場合は格段に遅くなります(SSD 化している場合はどうなんでしょうね?)。

ちなみに、現在、DB 速度の計測用にがんがんアクセスログを突っ込んで、2GB 近くまでデータベースを膨らましました。中身はアクセスログなので1つだけのテーブル。500万件ぐらい入っていると思う。

image

初期のSELECTで、SSD が 4.6秒、HDD が 15.1 秒。インデックスなしの全検索っぽいクエリを使っているのですが、3倍ぐらい早くなります。

imageimage

2回目以降のキャッシュが効いた状態だと、SSD,HDD ともに 0.4秒で返ってきます。

imageimage

こんな感じで、SQL Server が 4GB メモリを使っているので、ほとんどオンメモリですね。

image

大量ユーザーの外部サーバー向けだと、本式のSSDストレージを使わないとダメかもしれませんが、社内サーバーとか何かのプロジェクトでデータ解析とか位ならば、手ごろな SSD を買ってきて差し込んでおくのも悪くないスピードかと(ええと、このPCにはメモリが大量に積んであるので、そのあたりは別に検証をします)。

カテゴリー: データベース, パフォーマンス | SQL Server のデータベースファイルを SSD に移す はコメントを受け付けていません

SSDにするとBlukcopyは5倍ぐらい早くなる

せっかく、最強.NET開発PCにSSDを入れたので、SQL Serverがどれくらい早くなるか計測してみます。つーか、もともとその目的もあって、SSD にしています。大容量の SSD はそれなりにお高いので、本当なら 64GB ぐらいの安めのを買って試してみたいところなのですが、まだ買ってないので。

PLEXTRO PX-512M5P
http://www.goplextor.com/jp/index.php/m5-pro
WDC WD20EZRX-00DC0B0 1TB

という WD にあまりに不利な状況なのですが…まあ、ひと昔前の HDD と最新の SSD を比較するということでやってみます。状況としては、昔の HDD に SQL Server をがりがりやってチューニングして頑張って、という状況だけど、最近データアクセスが遅くて困る。となると、もっとチューニングをするのか、CPU を変えるのか、ソフトウェアをリプレースするのか?と色々考えるけども、HDD から SSD にデータベースを乗せ換えるだけでも十分じゃない?ってところです。

以下、100万件のWEBアクセスログを、BulkCopy でインサートして計測しています。100万件とは言いますが、実は大したことがなくて、実際に業務で扱うデータは1億件ぐらいと桁が2桁ぐらい違いますよね。以前は、この100万件扱うのにひいこら言っていたはずなんですが、CPU とメモリの関係なのか、結構スムースに動きます。なので、相対値としてみてください。

SSD にバルクインサート中

100万件インサートで 7.8秒
20130408_02
HDD にバルクインサート中
20130408_03
100万件インサートで 32.1秒

20130408_04

実測値で5倍ぐらいの違いが出ます。これは、大量のデータインサートなので、状況が特別なのですが、書き込みの場合でも SSD のほうが遥かに早い。

で、別途読み込み(SELECT)をやってみたのですが、こっちのほうはディスクキャッシュが効いていると、どちらも .3 秒とかで返ってくるので比較になりません。当然、インデックスがない状態でこれですから。SELECT のほうは、別途計測方法を考えてリトライしましょう。

■実験ソース

void GoBlukCopy(string CNSTR)
{
    DataTable dt = _dt;

    SqlConnection cn = new SqlConnection(CNSTR);
    SqlBulkCopy bc = new SqlBulkCopy(cn);

    DateTime start = DateTime.Now;

    bc.BulkCopyTimeout = 0;
    bc.DestinationTableName = "logs";
    cn.Open();
    bc.WriteToServer(dt);
    cn.Close();

    DateTime end = DateTime.Now;
    label2.Text = string.Format("BulkCopy完了 {0:#.0} sec",
        ((TimeSpan)(end - start)).TotalSeconds);
}

ついでにアクセスログから DataTable を作るところも。非同期を使っているので、別の記事にでも解説を。

DataTable _dt;
int _count;
bool _completed;
/// <summary>
/// ファイルから読み込み
/// </summary>
/// <returns></returns>
public async Task<DataTable> MakeDataTable()
{
    DataTable dt = new DataTable();
    dt.Columns.Add(new DataColumn("dt", typeof(string)));
    dt.Columns.Add(new DataColumn("code", typeof(string)));
    dt.Columns.Add(new DataColumn("ip", typeof(string)));
    dt.Columns.Add(new DataColumn("req", typeof(string)));
    dt.Columns.Add(new DataColumn("url", typeof(string)));

    _completed = false;
    await Task.Factory.StartNew(
        () =>
        {
            var sr = System.IO.File.OpenText(@"D:sitelogsout3.csv");
            _count = 0;
            while (sr.EndOfStream == false)
            {
                string line = sr.ReadLine();
                string[] v = line.Split(new string[] { "t" }, StringSplitOptions.None);
                DataRow row = dt.NewRow();
                dt.Rows.Add(row);
                row["dt"] = v[0];
                row["code"] = v[1];
                row["ip"] = v[2];
                row["req"] = v[3];
                row["url"] = v[4];
                _count++;
            }
            sr.Close();
            _completed = true;
            _dt = dt;
        });

    return dt;
}

private void button2_Click(object sender, EventArgs e)
{
    Task t1 = MakeDataTable();
    Task t2 = Task.Factory.StartNew(async () =>
    {
        while (_completed == false)
        {
            await Task.Delay(500);
            label2.Invoke((MethodInvoker)(() => label2.Text =
                string.Format("{0} 件読み込み中", _count)));
        }
        label2.Invoke((MethodInvoker)(() => label2.Text =
            string.Format("{0} 件読み込み完了", _count)));
    });
}
カテゴリー: C#, データベース, パフォーマンス | SSDにするとBlukcopyは5倍ぐらい早くなる はコメントを受け付けていません

Umbraco 6 をインストールする手順

実質、日本ではUmbraco CMS でウェブページを作ろう しか、Umbraco関連の情報がないのですが、ASP.NET MVCに対応しているということで支援がてら。自分でも使いたいので。

まずは、ローカルのIISにインストールして、いくらか弄った後に、ExperssWebあたりにアップすることを考えます。

■まずはローカルにIISを入れるところから

時々忘れるので、簡単に手順を書いておきます。コントロールパネルを開いて、「Windows の機能の有効化または無効化」を開きます。左上の検索ボックスで「機能の」とか打てばokです。

インターネットインフォーメーションサービス(IIS)をチェックして、「ASP.NET 4.5」を忘れずにチェックしておく。

 

# この図の影とか描画キャンバスは、適当なVBAマクロを作れば効率化できる。

インストールが終わったら、スタート画面で、「IIS」で検索して表示さればok。

ここで注意したいのは、Umbraco はドメインのルートにしか置けない。http://localhos/Umbraco とかはダメで、http://localhost:8081/ のように新しいドメイン≒Webサイトを作る必要がある。ルートのCSS のパスがルートからになっているので「バグ」でもあり「仕様」でもあり、ってところ。

 

■独自のWebサイトを作る

IISで「サイト」を右クリックして「Webサイトの追加」で作成。

ここでは、「c:siteUmbracoCms.6.0.3」を、Umbraco という Webサイトに割り当てている。

あらかじめ、Umbraco CMS – Home から UmbracoCms.6.0.3.zip をダウンロードしておく。

無事にできるとこんな感じに。

 

■Umbracoのインストール

いくつかパターンがありますが、練習しやすい SQL CE(ファイル型のデータベース)とテンプレートは Personal で作ります。

IISで作った http://localhost:8081 にブラウザでアクセスする。「イントラネットが~」と出るので「有効」にしておく。

インストーラーの画面が開かれるので「Let’s get start!」をクリック。

同意するために「Accept and Continue」をクリック。

 

インストールを簡単にするために「SQL CE 4」に切り替える。

新しい SQL Server のデータベースを作っても ok。

データベースのインストールが完了。Continue をクリック。

管理者のユーザー名とパスワードを登録。

今回は、練習のためPersonal を選択する。

好きなスキンを選択。これはあとで変えられます。

無事、サイトができあがったら、Set up your new website で管理画面を開く。Preview your new website のほうは初回だけ動きがおかしいので、触らないほうが無難。

こんな感じで、ページ単位で管理ができます。Wordpress の場合は、ブログが主体なので、こういうページ構成を作るのはちょっと苦手ですよね。最初にページ構成の計画を立てる必要ある。Umbracoの場合は、後からの差し込みが楽になります。

新しいタブを開いて、http://localhost:8081/ のようにサイトを開くと、こんな感じ。

■ページ構成を試してみる

管理画面は、http://localhost:8081/umbraco を開けばokです。スキンには「管理」へのリンクがないので、戸惑います。Wordpressのように「サイト管理」を表につけておいたほうが良いかも。

ページを作成するときには種類(テンプレート)を選択できる。たぶん、Blog Post と Textpageだけを使うようになるかな。

Blog Postの場合は、あらかじめ Siteのトップページにある、コンテンツ枠(?)に時系列で表示されます。Textpageのほうは、親ページから子ページへと移動させるときに便利です。

 

BlogPost の場合はこんな風に、トップにあるステークホルダに時系列で表示される。

 

子ページは、親ページから手繰れるようになっている。

細かい使い方は後日チェック。

 

 

 

 

 

カテゴリー: Umbraco | Umbraco 6 をインストールする手順 はコメントを受け付けていません

デスクトップ版のSkyDriveが同期できなくなった場合の対処方法

自分のメモ代わりに。

お客さんや自分の仕事ファイルの受け渡しに便利な SkyDrive なんですが(Dropboxから乗り換えた)、時々、同期中です…止まらなくなります。どうやら、SkyDrive で同期させるファイルが多すぎると、デスクトップ版のSkyDriveが途中でこけて同期できなくなるみたいで、対処方法はファイルを同期しなおすしかない…ってな感じらしいのですが、なんかないですかね?これで3回めなんですけど、ってな訳で、対処方法、というか対症療法を書いておきます。

image

以前の2回は、上記のような同期しっぱなしのフォルダをローカルとSkyDrive上で丸ごと消してから、ちまちまと復帰していたのですが、今回はダメ、2時間経っても再起動してもだめでした。どうも、Visual Studio 2012 で作ったソースファイルをそのままの形で SkyDrive に乗せるとダメなことが多く、ちまちま消しては zip に直していたのですが、なんか、これも手間だし、どうせならば一気に同期しなおしたほうが良さそう、ということで、以下の手順です。きちんとバックアップも取れるし、失敗はありません。

image

インジケータのところでぐるぐる同期している SkyDrive のアイコンを右クリックして「設定」。

image

「SkyDrive のリンク解除」で、いったん解除します。

解除すると、「SkyDriveを始めますか?」の画面が出るので、そのままにしておきます。

image

エクスプローラーで、c:user<ユーザー名>SkyDrive のフォルダ名を変更します。これでローカルのファイルがバックアップを取ったことになります。
同時に、「SkyDrive」というフォルダを作っておきます。

「SkyDriveをはじめますか?」の画面で、「始める」(だったと思う)をクリックして、Microsoft アカウントでログインします。

そのあと、先に作成した SkyDrive フォルダを指定します。

image

あとは、同期が終わるまでじっとまってます。いや仕事をしてもいいんですけどね。4.2GB ぐらいであれば、半日ぐらいで終わるかと(うちは ASDL の遅い回線なので)。光回線だったりすともっと早いですよね。復旧に時間はかかるけど、これが一番確実な方法かなと思ってます。

カテゴリー: トラブルシューティング | 1件のコメント

日本語Windows 8 Pro で Kindle を動かす方法

現時点で、Kindle for PC の日本語版はありません。英語版はあるそうなのですが、Amazon.com のアカウントに接続するそうで、Amazon.co.jp で買った日本の書籍は読めません。なんだかなぁ。素直に、iPad や Android で読めばいいのですが…コンピュータ書籍を資料として調べる場合は PC のほうがいいですよね。なんとかならないものか、と思って探していると、アマゾンの電子書籍、kindleをパソコンで読む | うらかんじ.com なところに、Android のエミュレータを使って、Kindle を動かすという方法が載っていました。BlueStacks は結構現実的に動くそうで、ひとまず Windows 8 で読めればいいか、ってな気分でやってみます。
Android だから変なアプリをダウンロードすると連絡先とかが…というリスクがありますが、エミュレータ上だし、他と同期をさせなければよいので、その点は安心です。まあ、何かを入れるたびに、たくさんの同意を求めるアプリは基本入れないということで。

実は、Kindle の本を買うのは初めてで(他の電子書籍は色々試したのですが)、そのあたり Kindle の購入自体も含めてメモ的に書き残しておきます。

■なにはともあれ、BlueStacks をインストールする。

エミューレターである BlueStacks を Windows 8 にインストールします。残念ながら Windows RT 版はないんですよね。作る予定はある、って1年前の記事に書いてはあるのですが、今はどうなっているのかよくわかりません。

http://www.bluestacks.com/
image

Windows 8 Pro なので、一番下の青いリンクをクリックします。Windows 7 ならば、緑色のリンクからダウンロードすれば ok です。

image

Continue してインストールしてしまいます。

image

このオプションもそのままで。

image

インストールが終わるといきなり、全画面で立ち上がります。そんな時は、下のメニューにある□のボタンを押して、ウィンドウモードにしましょう。メニューが出ない場合は、Win キーを押してスタート画面に戻り、再びデスクトップに戻ると表示されます。

image

これがウィンドウモードの場合です。

■続けて Kindle for Android をインストール

「アプリ検索」のアイコンをクリックして、キーボードから「kindle」と打ちます。キーボードはそのまま使えます(ただし、日本語変換ができないのでこれはあとから)。検索結果の中から「kindle for android」をマウスでクリックします。

image

最初の候補の「Kindle」のインストールボタンをクリックして、インストールします。

image

そのまま continue

image

アプリを同期するための google アカウントを入力します。ない場合は、ここでも作成できます。

image

ログインを押して

image

Google アカウントのユーザ名とパスワードを入れます。

image

日本語キーボードの場合「@」を打てないので、テキストボックスをマウスでダブルクリックしてソフトウェアキーボードを出します。

image

無事ログインができると「携帯の登録」が完了します。携帯=エミュレータなので、このエミュレータが1個分登録されたってことですね。

image

既に、他の携帯が登録されている場合は、同期(シンクロ)をします。私の場合、別の BlueStacks を登録したので、こんな感じになっています。

image

同期先を選んで、Done ボタンをクリックします。

image

無事、Google Play に入れそうです。で、実はここまでが Google Play への登録で、Kindle のインストールはこれからだったりします。再び、アプリ検索のアイコンをクリックして、kindle をインストールしようとすると、こんな画面がでてきます。

image

これの一番上にある kindle をクリックします。他のアプリは、いわゆる「ついで買い」を誘うやつですね。

image

Google play に同意。クーポンなどのチェックは外しても ok です。

image

やっとこさ、Kindle のインストールの画面が出てくるので「インストール」ボタンをクリック。

image

諸々の許可が必要なんですが、Amazon を信用して「同意してダウンロード」。

image

インストールが完了したら「開く」ボタンをクリック

■Amazon のアカウントでログイン

ここからは、Amazon の領域になるので、Amazon のアカウントを使います。

image

Amazon のアカウントでログインをすると、同期が始まります。

image

私の場合、既に1冊買ってあるので「クラウド」をクリックすると、既に Kindle で買った本が見れます。

image

こんな感じで読めるようになます。

■日本語入力アプリをインストールする

早速 Kindle で本を買いたいところですが、日本語入力ができないと検索などができません。なので、先に「日本語入力アプリ」を入れます。
下にあるホームボタンを押して、再び「アプリ検索」で「nihongo」とキーボードで打ちます。

image

色々あるのですが、ここは素直に「Google 日本語入力」をインストールしてみます。ついで買いの画面で一番上にあるアイコンをクリックします。

image

Google 日本語入力をインストール。

image

しばらくすると、Google 日本語入力のアイコンが出てくるのでクリック。

image

日本語入力を有効にします。「次へ」ボタンをクリック。

image

少し下にスクロールして「Google 日本語入力Beta」のチェックを入れます。

image

日本語変換の精度解析のために、間違ってクレジットカード番号とかも収集してしまう可能性がある訳ですが…まあ、クレジットカードはこの端末では入れないので、同意します。こうしないと、日本語が打てないので(別の日本語入力を選択してもいいですね)。

左下の戻る(←矢印)ボタンをクリックして入力キーボードを選択します。

image

無難に「QWERTY配列」を選択しておくとよいです。

■Kindle でお試し版を試してみる

いきなり買ってしまうのではなくて、お試し版(無料)をダウンロードしてみましょう。
ホームボタンをクリックして「Kindle」を起動させて、「ストア」に移動します。

image

右上の「ストア」をクリック

image

検索項目をダブルクリックして、ソフトウエアキーボードを出します。これを無視して、ハードウェアのキーボードでバシバシと変換していきます。

image

検索にマッチした本が出てます。試しにひとつクリックしてみます。

image

注意しなければいけないのが「1-Click」ボタンのほうは、即購入になります。クレジットカード引き落としになっている即買いになってしまうので、タッチしないようにします。大抵の場合は、無料サンプルはついているようなので「無料サンプルを試す」ボタンをクリックします。

image

「今すぐそれを読む」をクリックして、Kindle のリーダーに戻ります。

image

小説のように文章の場合は、スムースに動くのですが、漫画の場合はかなりもたつきます。でもまあ、それなりに読めます。

image

購入した本と無料サンプルは、こんな風に並んでいます。

端末を登録しておくと、PC で Amazon のサイトを開いたときに、どの端末に送るのかを選択できます。なので、購入する場合は、PC で選択したほうが便利かと。

image

こんな風にすると、日本語版の Windows 8 でも Kindle が読めるよ、ってことなんですが、なんともややこしいし、iPad を持っていればそれを使えばいいので、まあ資料的な役割ということで使うとよいかと。

■Kindle のリーダーは何がいいのか?

なんで、こんなやこしいことをやったのかと言うと、ちょっと高めの「Pro ASP.NET MVC 4」という洋書を買いたかったのです。ペーバーバックで 5,100円、Kindle 版で2,800円なので、断然 Kindle 版が安いのですが、iPad/iPhone でしか見れないというのは結構なハンディなんですよね。紙だと書き込みをしたり、最終的にはばらしてしまったり、コピーを取ってみたりできるのですが、iPad で閲覧をしていると、ちょっとそのあたりができない。で、Amazon.com で買えば、英語版の Kindle for PC があるし、それでもいいかと思って覗いてみると、ペーパーバックもKindleも30ドルで、少しだけ Kindle のほうが高いんですよね。うーん、なんだかな、と思って、探していたのです。

ちょっと副作用的にいいかなと思ったのが、エミュレーター上なので画面キャプチャが取れることです。基本印刷とかはできないのですが、これだと画面キャプチャして部分的に切り取って OneNote とか evarnote に使えそうですね。もともと、そういう機能を Kindle も持っていると思うのですが、PC 上だとツールの類で色々いじれるので、結構重宝しそうです。

あと、iPad で読んでいるときに気づいたのですが、ここまで読んだってのを同期してくれます。なので、iPad でパラパラと読み進めたとこまで、PC で Kindle を開いたときに「ここまで読んだ」という場所までジャンプしてくれます。これは、気の利いた機能で、どの端末で読んでもまるで「一冊の本を読んでいる」という気分にさせてくれます。

そんな訳で、活用法のほうは後日。

追記:2014/10/01
現時点で、ブラウザで読む Kindle Cloud Reader という方法があります。漫画本や洋書に限られていますが、順次、縦書きの日本語の本にも対応されそうです。Kindle Launcher は、スタート画面に Kindle 本をピン留めできるツールですので、活用してみてください。

カテゴリー: 雑談 | 日本語Windows 8 Pro で Kindle を動かす方法 はコメントを受け付けていません

[C#] クリップボードからビットマップ形式のデータを拾って、連番でフォルダに保存する

新人プログラマー向けシリーズ…ではなくて、チープだけど今まで手順が面倒だったのでツールに。

機能的には、クリップボードのビットマップ形式のデータを取り出して、特定のフォルダに連番で保存するだけで、という単発機能です。しかも、保存先はソースコードに書き込んでしまっているので、他で使う場合にはコンパイルし直さないという、私家版≒ダメツールです。設定ぐらいは後で、config に書き直すとして。

いままでの手順が、

  1. クリップボードで画面キャプチャ
  2. IrfanViewに貼り付け。
  3. ファイル名を「日付_連番」にして、特定のフォルダに保存
  4. エディタに [img 日付_連番] の形式で追加

だったのですが、1,2,3,4 は自動化できますよね。時々、2 で IrfanView に貼り付けた後に切り取ったり、縮小したりするので、必ずしも自動化とはいかないのですが、ほぼ1から4は同じ手順になっています。なので「ツール」にしてしまうということです。ブログへの up は、QX エディタで描いて、適当な perl スクリプトを通してアップします。その時に画像のサムネールやら拡大画像やらは C# で作った自作ツールです。なんで、こんなややこしい?ことになっているかというと、本当は Windows Live Writer で統一したいところなのですが、Live Wirter の場合はコードがうまく表示できない。Wordpress の場合は、インラインタグというのがあって、

...

と書くと、SyntaxHighlighter のプラグインを入れておけば、コードにハイライトを付けてくれます。これをローカルで編集する場合は、まあ、適当なテキストエディタのほうが良い訳で、、いくつかのツールを組み合わせて書いているという具合。あまり、ブラウザのエディタを使わないんですよね…というタイプなので。

■クリップボードからビットマップを取得する

private void buttonClip_Click(object sender, EventArgs e)
{
    var clip = Clipboard.GetDataObject();
    // 画像ファイルのみ取り込み
    var bmp = clip.GetData(typeof(Bitmap)) as Bitmap;
    if (bmp == null) return;
    // ピクチャへ表示
    pictureBox1.Image = bmp;
}

とするだけで ok。PictugeBox は自動で拡大されないように SizeMode を Zoom に変更しておきます。

# ここに矢印とか簡単に付けられるツールを作らないと。
# あと、切り取った場合は、切り取り線みたいなのとか。

■指定のフォルダに連番で保存する

private void buttonSave_Click(object sender, EventArgs e)
{
    Bitmap bmp = (Bitmap)pictureBox1.Image;
    if (bmp == null)
        return;

    ImageFormat fmt = ImageFormat.Bmp;
    if (radioButton1.Checked) fmt = ImageFormat.Bmp;
    if (radioButton2.Checked) fmt = ImageFormat.Jpeg;
    if (radioButton3.Checked) fmt = ImageFormat.Png;
    string fname = MakeFileName(fmt);
    bmp.Save(fname, fmt);

    textBox1.Text = "[img " + Path.GetFileName(fname) + "]";

}

string MakeFileName(ImageFormat fmt)
{
    string path = FOLDER ;
    DateTime dt = DateTime.Now;
    string dname = string.Format("{0:0000}{1:00}{2:00}", dt.Year, dt.Month, dt.Day);
    var files = System.IO.Directory.GetFiles(FOLDER);
    var file  = files.Where(f => f.IndexOf(dname + "_") > 0).Max();
    if ( file == null ) {
        path += dname + "_01." + fmt.ToString();
    } else {
        var mat = new Regex( @"_(d+).").Match(file);
        int num = int.Parse( mat.Groups[1].Value );
        num++;
        path += dname + "_" + num.ToString("00") + "." + fmt.ToString();
    }
    return path;
}

ファイル名がユニークであればよい、というのと拡張子に関係なく日付でソートしたい時がある(名前でソートをすると古い順になるので)連番のほうをインクリメントしていきます。ここでは、フォルダからファイルを拾ってきているのでだんだん遅くなってしまう可能性があるのですが、まあ、良しということで。これはツールの config に連番を付けてもよいのですが、手作業で番号を入れたい時にちょっと困るので、フォルダからいちいち拾ってきます。

■ショートカットを設定する

なんどか使ってみて追加した機能が、ショートカットです。「取り込み(V)」となっているので、Alt+V で取り込みボタンを押せるのですが、何度も、Ctrl+V と間違えて押します。コピー&ペーストだから、Ctrl+V のほうが自然なんですね。なので、自然なほうに合わせて、フォームの key 取得のところで Ctrl+V を有効にします。

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Control == true)
    {
        if (e.KeyCode == Keys.V)
        {
            buttonClip_Click(sender, null);
        }
        else if (e.KeyCode == Keys.S)
        {
            buttonSave_Click(sender, null);
        }
    }
}

そのままだと、フォーカスのあるボタンにキーイベントが飛んでいくので、フォームの方に来るように Form の KeyPreview プロパティを True にするのを忘れずに。

ちなみに、QX エディタでの編集状態はこんな感じになっています。

# QX エディタで img のところにカーソルをあてるとプレビューができるプラグインとか作れないですかね?

サンプルソースはこちら
http://sdrv.ms/10qU0yT

zip ファイル

AutoSaveCap-v0.1-src.zip

# この SkyDrive への登録部分も手間を省きたいところ。

アイコンは、84個のデスクトップアイコン | アイコンを創造するアイコン素材専門館アイコンゲータ- から借りてます。

カテゴリー: 開発, C# | [C#] クリップボードからビットマップ形式のデータを拾って、連番でフォルダに保存する はコメントを受け付けていません

Surface RTに動画用のストレージ(microSD)を増設する

Surface RT 32GB タイプは5万円を切る値段なのですが、OS 自体に10GB以上、Office が入っている分、SSD の容量が取られるので、なんやかやといれていくと残りがが10GB だったりします(もうちょっとあったような気がするけど、私の Surface RT は、現時点で残容量 9GB です)。

音楽とか Word でドキュメントとかを入れている分には、このぐらいでも大丈夫?なのですが、動画を入れたり、3D ゲームを入れたりすると結構圧迫するのが予想されます。そういうハードな使い方をする場合は、あらかじめ 64 GB タイプを買えばいいのでしょうが、幸いにして Surface RT は micro SD のインターフェースを持っているので、これに大容量の SD カードを差し込めば ok … ってなことはできるかな?と。

ちなみに Surface の microSD を入れるところはここです。

20130401_01

Surface RT のスペックはこちら。

価格.com – マイクロソフト Surface RT 32GB 7XR-00030 スペック・仕様

USB のほうは、マウスとかで開けておきたいので、microSD, microSDXC のほうを使います。SDメモリーカード – Wikipedia を見ると、いくつか種類があるので候補を挙げれば以下なところです。

  • SDHCメモリーカード 32GB Class 2
  • SDHCメモリーカード 32GB Class 4
  • SDHCメモリーカード 32GB Class 10
  • SDXCメモリーカード 32GB Class 10

クラスによる違いは、以下の通りだそうです。

カード 最低保障レート
Class 2 2MB/sec ( 16Mbps )
Class 4 4MB/sec ( 32Mbps )
Class 6 6MB/sec ( 36Mbps )
Class 10 10MB/sec ( 80Mbps )

値段的に言えば、

な感じで、microSDHC だったら Class 4, 10 であまり変わらない(数百円程度)なので、新しく買う場合は Class 10 にしておいたほうが良いかな、という感じですね。大容量の microSDXC のほうは魅力的ではあるのですが、さくっと買うにしては値段が高い。

もし、手元にあるならば、Class 4 の microSD カードを使いたいわけで、Amazon.co.jp: A-DATA MicroSDHC 8GB Class6 SDアダプタ-付属 MCSDHC8GB/2A/Class6: パソコン・周辺機器 あたりを使い回すことはできないかな?と考えてみます。

■理論値を計算する

例えば、DVD が 8GB として2時間の映画が入っているとすると、8GB/(2時間*60*60) = 1MB/sec の読出しになります。実際は読出しの後に mp4 のデコードをしてなどなどやっているので、読出しのスピードはもうちょっと早くないといけないのですが、読み込みとビデオ描画が「完全にパラレル」で動いた場合には、1MB/sec 程度あれば十分ってところです。DVDの読み取り速度は何MB/sなんですか? – Yahoo!知恵袋 を見ると、等倍速の場合は、1.385MB/sec なので、まあ、だいたいあっているみたいですね。

■では、古いタイプの SD カードで十分なのか?

DVD のような高解像度の場合でも、Class 2 の転送速度(2MB/sec)で十分な訳だからわざわざ Class 10 を買わずに済みますよね…って方向でいきたいのですが、ちょっと事情が異なります。

ネットワーク経由で、Surface RT のビデオアプリを使うと、ホストしている PC の送信速度はかなり上下します。ピーク時で、8MB/sec を超えるところがあると思えば、数秒ほど 0 MB/sec になります。WiFi では十分な速度があるのですが、動画の mp4 のデータを断続的に送って、Surface RT でデコードして描画というのを繰り返しています。

image

このため、WiFi(無線LAN)を使って Surface RT で動画を表示しようとすると、ホスト側のスピードが遅いとコマ落ちが発生します。多分、MeoBankSD | 製品情報 | TAXAN MeoBank を使ったときに SD カードが Class 4 だと動画がかくかくしていて、Class 10 に変えるとスムーズになった、というのはこの現象だと思います。mp4 あたりの転送とエンコード方法の規格?には詳しくないのでわかりませんが、ネットワークのデータ転送量を見る限り、同じだと思います。ネットワークの場合は、瞬間的な読み込み時に 7MB/sec 位が必要になるので、一時的に Class 4, 6 の速度を超えてしまうので動画が止まってしまう状態になるかと。なので、SD メモリを読み出すときに Class 10 であれば、動画がスムースに動くわけです。

■ローカルの SD カード読出しはどうなのか?

mp4 の読み込みが平均的ではないことが分かったので、今度はローカルストレージの HDD から起動した場合を確認します。これは Surface RT ではなくて、普通の PC で同じビデオを表示したときです。

image

E ドライブの mp4 の動画を流しているときのピークは 1MB/sec 程度になっています。無線LAN経由と同じく、断続的にデータの読出しを行っていますが、ピーク時の転送量が少ないのは…よくわからないのですが、ネットワークのエンコードとか、その関係ですかね? ネットワーク経由よりもピーク時の転送量が少ない(Class 2以下)ので、Class 4の昔の microSD を使いまわせるのでは?と考えられます。

■実際 Surface RT で実験してみる

手元にあった Class 6 の microSD で試してみました。プログラム自体は 200KB/sec で読み込んでいるので、読み取り速度としては十分なような気がするのですが、ピークの出方をみると断続的に読み取りをしていますね。

image

動画のほうはどうなのかというと、エンコードなりサイズの問題もあるでしょうが、ローカルの D ドライブから(SD カード)断続的にデータを読み込んでいて、カメラがパンをしたような背景が大きく動くときは、ちょっとかくかくした感じになります。CPU 自体は大丈夫なので、どうやら読み取りスピードが足りていないようです。同じ mp4 のデータを Cドライブ(内蔵の SSD)にコピーして動かすと、400KB/sec 程度の読み込みが発生して、動きがスムースになります。どうやら、Class 10 にしないと転送量は足りないようです。

■結論としてはどうなのか?

後で実測しないとダメなのですが、microSD から直接動画を表示する場合は、Class 10 を使わないとスムースな描画ができません。サイズの微調整をするか、アプリ側で調節をすればよいのでしょうが、現状では数百円の差ならば Class 10 の microSDHC や microSDXC に買い替えたほうがよさそうですね。ひとまず 32 GB の microSDHC で試してみようと思います。

ただし、少し懸念点があって、内部 SSD が結構なスピードなので、Class 10 でも速度が足りているのか?がちょっと問題です。平均?転送速度が 400KB/sec と Class 6(6MB/sec) の読み込みの倍になっているので、Class 10 の 10MB/sec で足りるのかどうかが、ちょっとわかりません。このあたりは、後日実測してみましょう。

もうひとつ方法があって、Class 6 のような古い SD メモリでも、バッチを作ってやって、一度内部の SSD にコピーしてから動画を表示する、というパターンでもいいですね。転送自体は数秒で済むので、そんなに負担にはならいでしょう。大体、2時間弱の映画が mp4 で 1GB 程度なので、古い映画を 30本ぐらい入れることができます。このあたりは色々試してみたいところです。

カテゴリー: windows 8 | 1件のコメント

ビックデータから有用な情報を導き出す方法

ビッグデータという、99%の事業者には効果の無い話(山本 一郎) – 個人 – Yahoo!ニュース
http://bylines.news.yahoo.co.jp/yamamotoichiro/20130328-00024117/
ビッグデータは、そうやって使うもんじゃないんじゃない?そもそも・・・ – ウィリアムのいたずらの開発日記
http://blog.goo.ne.jp/xmldtp/e/cd13de092ea5ab00023e18539234078f
ローソンのビッグデータは、なぜ山本一郎氏に叩かれるほどの成果しか出なかったのか? – ウィリアムのいたずらの開発日記
http://blog.goo.ne.jp/xmldtp/e/f6aa4b0ee88352c8bf5b91e2816ce296

久々に「ウィリアムのいたずら」さんの日記を見つけたので、続けて考察してみる。もちろん、Yahoo ニュースのほうは的はずれ。

■ビックデータの定義とは?

定義っていうほどではないのだろうけど、ローソンのPONTAの例で言えば、かつてPOSシステムがなかった時代から、POSの導入で商品の出入りの管理をして、それを個人に紐づけることができたという時代/技術の流れがあって、それを一次元的に集約できるようになったのが「ビックデータ」ってことで ok ですかね? このときのデータはジャーナル的なデータでしかなくて死蔵されているデータ。単なるロギングとも言えますね。これを「ビックデータ」として活用できるためには、

  • なんらかの形で、データを加工できるマシンパワーがある。

ことが必須。統計的にサンプリングするのもありなんですが、サンプリングすると、

  • 誤差なりノイズなりが消えてしまう
  • 局所データが消えてしまう

という不都合があるわけで、ビックデータからの抽出作業(特異なノイズや特徴量など)ができるマシンパワーが必要なわけで、宇宙人探しのアレと同じパターンです。

■ビックデータから何を導き出してはいけないのか?

いけない訳じゃないけど、意味がないよ、ってのは

  • なんらかの平均値を出す
  • なんらかの中央値を出す
  • なんらかのヒストグラムを出す

というようなことは統計学上、サンプリング理論で十分なので、やっていはいけない…というかデータのサンプリングで十分。ウィリアムのいたずらさんの書いてある「紅白歌合戦」の傾向みたいなのですね。詳しいことはサンプリング理論を読んで貰うとして、サンプリングの分布が本来の分布を表すためのサンプリング率というのが算出できます。それに沿ってデータをランダムに抜き出せば、ビックデータを扱うほどのマシンパワーがなくても簡単に統計がとれます。大きなデータを解析するという意味では、7百万件のデータから1秒以内に波形表示をする – Moonmile Solutions Blog の手法を取れば良い訳です。

なので、単に相関図を出したり、年代別の傾向を出したり、県別のデータを出したりしてレポートを造るのは「ビックデータ」を活用している、といはは言えません。いや、10年前ぐらいだと、そのぐらいのデータを処理するために十分アップアップだったわけで、月次なり日次なりの帳票を出すだけでも一苦労だったんですけどね。最近だと、適当なクエリを書くだけで十分です。あと各DBには統計関数が揃っているし。全体を眺めてマクロ的な統計はあまりいらないのです。

■ビックデータから局所の傾向を導き出す

具体的に何が活用できるかというと、PONTA の例をとると、

  1. 全国の購入データが本社に集まってくる
  2. 県別に平均を取ると、A市の売り上げが悪いことが分かる
  3. A市の顧客数、顧客の来る時間帯、商品の品揃えを全国平均、あるいは優秀店舗と比較する。
  4. A市の商品の品揃えを変更した場合、売上が変わるかシミュレーションする
  5. 実際に商品入れ替えを行い、シミュレートとの誤差を比較して、4へフィードバックする。

ということが本社のビックデータで可能になるということです。1と2の平均計算は、通常のマクロの統計学の範囲で計算ができます。計算スピード自体は、先のサンプリングだけで十分です。全国の平均がでれば、平均以下の店舗の一覧は簡単に抽出できます。これもいままでのデータ解析の範疇でできます。

3のところから、ビックデータの活用範囲になります。全国区のサンプリング数ではA市のサンプリング数とは異なります。優秀店舗(売上がよい店舗)と全国平均、とA市の店舗の売り上げ、顧客の来店時間などを比較します。仮説として、A市が全国平均と同じパターンの人が住んでいれば、全国平均と同じ売上が上がるはずです。さらにA市が優秀店舗と同じ生活パターンの人が住んでいれば、A市の店舗は優秀店舗になったはずです。ですが、A市の売り上げが悪いとうことが、人の分布、生活パターン、嗜好などが、全国平均や優秀店舗のものと異なっているから、というのが原因です。

A市の店舗が優秀店舗になるためには2つの方法があります。

  • A市に住んでいる人を、優秀店舗に住んでいる人と同じように変える。
  • A市に住んでいる人の生活パターンに、A市の店舗を変える。

ということです。時には「人」を変えることも可能なのですが(ええ、会社とか)、コンビニの場合には無理な相談なので、店舗の方を変えます。当たり前ですね。
なので、A市の店舗の商品別売り上げと全国平均、優秀店舗のそれと比較して、違いを割り出します。特に優秀店舗では売れているけれども、A市では売れていないものを導き出します。いままのPOSシステムとデータ解析では、ここまで細かくチェックはできずに、全国区の売れ筋商品をA市の店舗にも入れるというスタイル(大衆スタイル)を取っていたわけですが、ネットの普及、細かい対応が可能になってきたので、A市の生活スタイルにあった販売方法(分衆スタイル)が取れます。

そこで、いままではA市の店舗の自己努力(勘とか営業マンが行ってのリサーチとか)になっていたわけですが、商品入れ替えによってA市の店舗の売り上げをシミュレートします。シミュレーションに関しては、地方販売、棚の設定、顧客の時間帯(通勤客、地元の生活客など)を加味したパターンを用意して一気にシミュレートします。商品入れ替えによる売上の確率は、他市の過去の商品入れ替えによる売上の上下による確率を加味させます。

こうすることで、A市で売り上げが上がるであろう商品の品ぞろえ、棚、戦術が生まれます。ここまでシミュレートでしかないので、実際に棚を変えたときに売り上げが変わるのかどうかを、日々のPONTAと、POSで抽出します。PONTA を出さない人もいますからね。そうやって、シミュレーションの結果と現実を比較して、A市の店舗の売り上げが上がるように調節しています。

ってのがビックデータの活用例です。これが、いままでのサンプリング方式やアンケート方式ではできないのが、

  • ボトムアップ方式による、A市と全国区との違いを抽出
  • A市の生活スタイルに合わせて、商品レイアウトを決定する
  • 多数のシミュレーションを行う
  • 商品レイアウト変更後の効果をシミュレーションに反映させる

ということが、いままではできません。かつ、単なるPOSシステムの場合には、商品レイアウトの変更案は作業量的にそれぞれの店長任せになるか、全国区の統一レイアウトにならざるを得ないのですが、本社に蓄積されているビックデータを活用することによって、本社から各店舗への個別提案が出せます。以前(と言っても5年以上前ですが)、テレビでみた店舗のレイアウト変更は、3ぐらいまでは店長単位でできていたので、3のあたりを本社が代行したり、シミュレートしたりすることが可能になります。いや既になっているかな?

■数学理論的ビックデータを扱うのは簡単だが

そんな訳で、数学的にビックデータを扱って局所に適用させるのは簡単なのですが、実際のところで難しいのは優秀店舗と平均以下店舗の「違い」をどの物理パラメータ(商品売り上げ、顧客年齢、顧客の来店数など)に割り当てるかですね。時々、これらを論理パラメータ(商品の色、季節商品など)に集約させてしまって見間違えることも多いのですが、まあ、全体売り上げからみると誤差の範囲になってしまうし、そのあたりは「ビックデータから大した情報は引き出せない」という間違った結論に達してしまうのかなと。

カテゴリー: 雑談 | ビックデータから有用な情報を導き出す方法 はコメントを受け付けていません

[WinRT] ストアアプリで DoEvents を実現する

[tweet https://twitter.com/biac/status/317963665636732928 ]

を見て Task.Yield() を早速試してみました。ループ待ちとしては、連続したアニメーションをつなぐために、await/async を使う  のパターンになるかなと。

■Application.DoEvents はどう実装するのか?

かつて、VB では画面の更新に DoEvents を使っていたわけで、これが結構便利。プログラムの for ループの中に DoEvents を差し込めば、画面(UI)を再描画してくれるのでループ内のカウンタ表示とか、キャンセルボタンを押すために DoEvents を入れたものです。似たパターンでは、VC++ でも Message ループを差し込んだり、VB.NET で Appliction.DoEvents を入れていました。
が、ストアアプリの場合は、この便利な DoEvents がないのです(確かに、WPFのほうにもないですね)。これをどう実現するのか?ってのが WPF 時代の人は知っているのでしょうが(あまり WPF はハードにタッチしていないので)、.NET 4.5 の場合は、async/await と Task を使いましょう、ってのが本来の姿。長いループの場合は、適宜 Task にして事項しましょう、ってのが推奨パターンです。

が、いちいち Task にするのが面倒臭いのと、Task の中から UI を触れないので Task の中では UI に対して Invoke をするか、ディスパッチをするか、というちょっと面倒なことをしないといけません(多分、まとめたページが世の中に既にあるはず)。

こんな風に、

  • Task.Yeild を使うパターン
  • Task.Delay を使うパターン
  • Task を使うパターン

の三種類で試してみます。いわゆる「重たい処理」というのが、アニメーションの完了待ちになっているので実は重い処理とは違うので、コードがちょっと違いますが、まあ応用が利くかと。

■Task.Yeild 待ちのパターン

private async void Button_Click_1(object sender, RoutedEventArgs e)
{
    bool completed = false;
    sbMove.Completed += (_, __) => { completed = true; };
    text1.Text = "アニメーション開始";
    int i = 0;
    sbMove.Begin();
    while ( completed == false ) {
        count1.Text = i.ToString();
        await Task.Yield();
        i++;
    }
    text1.Text = "アニメーション終了";
    sbMove.Stop();
}

開始と終了とにメッセージを TextBlock に表示します。また、ループの間にカウンタを表示。アニメーションの完了待ち(Completed イベント待ち)という「軽い処理」をしてるので、この Task.Yield() の処理は相当重たくなっています。実際に「重たい処理」が入れば、即時戻ってくる Task.Yield() はそれなりに使いでがあるかと。

■Task.Delay 待ちのパターン

private async void Button_Click_2(object sender, RoutedEventArgs e)
{
    bool completed = false;
    sbMove.Completed += (_, __) => { completed = true; };
    text1.Text = "アニメーション開始";
    int i = 0;
    sbMove.Begin();
    while (completed == false)
    {
        count2.Text = i.ToString();
        await Task.Delay(100);    // ちょっとだけ待つ
        i++;
    }
    text1.Text = "アニメーション終了";
    sbMove.Stop();
}

一見すると、Task.Yield() と変わらないように見えますが、Delay メソッドでミリ秒だけ待ちます。Delay メソッドは非同期(UIスレッドに処理を戻す)仕様なので、await を付けて結果的に Yield メソッドと同じ結果を得られます。本当に重たい処理をする場合には、Task.Delay(1); のように瞬時だけ処理を戻すというパターンでも使えます。
後で実験してみますが、Yeild よりも Delay のほうが処理が軽くなります。

■別 Task にするパターン

private async void Button_Click_3(object sender, RoutedEventArgs e)
{
    sbMove.Completed += (_, __) => { _completed = true; };
    sbMove.Begin();
    text1.Text = "アニメーション開始";
    await WaitComplete();   // 完了待ち
    text1.Text = "アニメーション終了";
    sbMove.Stop();
}
bool _completed = false;
///
/// 完了待ち
///
///
private Task WaitComplete()
{
    return Task.Run(async () =>
    {
        while (_completed == false)
        {
            await Task.Delay(100);  // ちょっと待つ
            // ここをコメントアウトしてもスムースに動く
        }
    });
}

おそらくこれが正式な方法で(もう少し良いパターンがあるような気もしますが)、完了待ちを別のタスクにします。_completed がグローバル扱いになるのが難点ですが、これはひと工夫(refを使うとか)すれば消えるはずです。WaitComplete メソッド内のタスクは UI とは別スレッドのために UI にあるカウンタの更新はできません。なので、ちょっとした小細工をするときには面倒といえば面倒ですね。

ただし、このコードの利点としては、await Task.Delay(100); の部分をコメントアウトして、ループだけにしても他のアニメーションがスムースに動くということです。これは async/await の戻りが UI スレッドではなくて、ワーク用のスレッドに戻るからなんですね。なので UI スレッドに負担を掛けずにすみます。なので、uI の応答性を重要視する場合はこのパターンで書くことになるでしょう。

■実測してみる。

Yeild と Delay の UI スレッドへの負担を見てみると。

アニメーションが 5秒の場合には、Task.Yeild は 7万回以上呼び出されているのに対して、Task.Delay は 44回で済みます。Delay が 50回呼び出されていないのは、まあ誤差の範囲で。
ちなみに、シミュレーターの場合は Task.Yeild では動きがかくかくしていますが、ローカルコンピューターではスムースに動いています。でもまあ、5秒間に7万回呼び出しても仕方がないわけで、CPU を喰わない(省電力化)をするためも、Delay のほうがお得かという結論です。

サンプルコードはこちら。
http://sdrv.ms/10mK1ch

zip ファイル

SampleDoEvents-v1.0-src.zip

カテゴリー: C#, WinRT | 2件のコメント