[WinRT] Surface RT で閲覧しているURLをデスクトップに送る

[WinRT] デスクトップで閲覧しているURLをSurface RTに送る – Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/4718

の逆向きパターンで、タブレットPCからデスクトップのほうにURLを送ります。

こっちのほうは、比較的簡単?で、タブレットPCで動作しているブラウザ(IE10)から共有を使って、ストアアプリに送信、そのストアアプリからデスクトップアプリに通信させます。簡易HTTPサーバーを立てるところは、前回と同じなので流用してます。というか同じアプリに乗せています。

■簡易HTTPサーバー

///
/// フォームロード時
///
///
///
private void Form1_Load(object sender, EventArgs e)
{
    listener = new HttpListener();
    listener.Prefixes.Add("http://*:8090/");
    listener.Start();

    // 受信待ちタスク
    Task tsk = new Task(
        () =>
        {
            while (true)
            {
                var cont = listener.GetContext();
                var req = cont.Request;
                var res = cont.Response;
                if (req.RawUrl.StartsWith("/GetUrl"))
                {
                    Debug.WriteLine(string.Format("req {0}", req.RawUrl));
                    var tw = new StreamWriter(res.OutputStream);
                    tw.Write(_text);
                    tw.Close();
                    res.Close();
                }
                else if (req.RawUrl.StartsWith("/PutUrl") == true)
                {
                    Debug.WriteLine(string.Format("req {0}", req.RawUrl));
                    var text = req.RawUrl.Replace("/PutUrl/", "");
                    text = System.Uri.UnescapeDataString(text);
                    textBox1.Text = text;
                    var tw = new StreamWriter(res.OutputStream);
                    tw.Write("OK");
                    tw.Close();
                    res.Close();
                }
                else
                {
                    var tw = new StreamWriter(res.OutputStream);
                    tw.Write("ERROR");
                    tw.Close();
                    res.Close();
                }
            }
        });
    tsk.Start();
}

同じ8090ポートを使って、/GetUrl の場合はデスクトップからタブレットPCへ、/PutUrl の場合はタブレットPCからデスクトップへ通信をします。
まあ、先行きは XML シリアライズを使って実装しますが、ひとまずこれで使い勝手を確認。

■共有ターゲットの実装

ブラウザから「共有」の対象になるために、連携するストアアプリを共有ターゲットにします。
追加で「共有コントラクト ターゲット」を追加してから、以下の部分を修正。

□共有コントラクトを開いたとき

public async void Activate(ShareTargetActivatedEventArgs args)
{
    this._shareOperation = args.ShareOperation;
    // ビュー モデルを使用して、共有されるコンテンツのメタデータを通信します
    var shareProperties = this._shareOperation.Data.Properties;
    var thumbnailImage = new BitmapImage();
    this.DefaultViewModel["Title"] = shareProperties.Title;
    this.DefaultViewModel["Description"] = shareProperties.Description;
    this.DefaultViewModel["Image"] = thumbnailImage;
    this.DefaultViewModel["Sharing"] = false;
    this.DefaultViewModel["ShowImage"] = false;
    this.DefaultViewModel["Comment"] = String.Empty;
    this.DefaultViewModel["SupportsComment"] = true;
    Window.Current.Content = this;
    Window.Current.Activate();
    // ブラウザからURLを共有する
    if (this._shareOperation.Data.Contains(StandardDataFormats.Uri))
    {
        var uri = await this._shareOperation.Data.GetUriAsync();
        this.DefaultViewModel["Comment"] = uri.ToString();
    }
    // 共有されるコンテンツの縮小版イメージをバックグラウンドで更新します
    if (shareProperties.Thumbnail != null)
    {
        var stream = await shareProperties.Thumbnail.OpenReadAsync();
        thumbnailImage.SetSource(stream);
        this.DefaultViewModel["ShowImage"] = true;
    }
}

□共有コントラクトで Share をタップしたとき

private async void ShareButton_Click(object sender, RoutedEventArgs e)
{
    this.DefaultViewModel["Sharing"] = true;
    this._shareOperation.ReportStarted();
    // TODO: this._shareOperation.Data を使用して共有シナリオに適した
    //       作業を実行します。通常は、カスタム ユーザー インターフェイス要素を介して
    //       このページに追加されたカスタム ユーザー インターフェイス要素を介して
    //       this.DefaultViewModel["Comment"]
    if (this._shareOperation.Data.Contains(StandardDataFormats.Uri))
    {
        // テキストデータを保存
        var text = this.DefaultViewModel["Comment"] as string;
        string url = "http://mars:8090/PutUrl/" + System.Uri.EscapeUriString(text);
        HttpClient cl = new HttpClient();
        var res = await cl.GetAsync(new Uri(url));
    }
    this._shareOperation.ReportCompleted();
}

実は、Active がなくていきなり share してもいいんですが、まあ、テンプレートのままで使ってみます。
こうすることで、

  1. ブラウザで閲覧する。
  2. チャームで「共有」を開いて GoRTApp を選択する。
  3. URL を確認してデスクトップに URL を通知する。
  4. デスクトップアプリのほうで、URL をブラウザで開く。

という流れができます。

■サンプルソース

サンプルソースはこちらで。

仕組みはこんな感じ。

20130422_02

カテゴリー: C#, WinRT | [WinRT] Surface RT で閲覧しているURLをデスクトップに送る はコメントを受け付けていません

[WinRT] デスクトップで閲覧しているURLをSurface RTに送る

サブノート/サブディスプレイに Surface RT を使っていると、デスクトップで見つけた Youtube を Surface で表示したい時が頻繁にあります。この場合、どうやって送るかというと…

  1. Twitter でメモ的に流してから、Surface 側で拾う
  2. SkyDrive に URL を置いてから Surface で拾ってくる。
  3. ちまちまと URL を Surface で打つ

という方法があるわけですが、どれも面倒くさい。ただし、Windows 8 同士であれば、デスクトップアプリでさっくりとできそうなのですが、片方が Windows RT なものだから、Windows ストア アプリしないといけないという制限がある。

image

で、前々から考えていた、デスクトップPCのほうに簡易HTTPサーバー、タブレットPCにWindows ストア アプリのクライアント、というパターンで実装してみます。

■簡易HTTPサーバー

/// <summary>
/// フォームロード時
/// </summary>
/// <param name=&quot;sender&quot;></param>
/// <param name=&quot;e&quot;></param>
private void Form1_Load(object sender, EventArgs e)
{
    listener = new HttpListener();
    listener.Prefixes.Add(&quot;http://*:8090/url/&quot;);
    listener.Start();

    // 受信待ちタスク
    Task tsk = new Task(
        () =>
        {
            while (true)
            {
                var cont = listener.GetContext();
                var req = cont.Request;
                var res = cont.Response;
                Debug.WriteLine(string.Format(&quot;req {0}&quot;, req.RawUrl));
                var tw = new StreamWriter(res.OutputStream);
                tw.Write(_text);
                tw.Close();
                res.Close();
            }
        });
    tsk.Start();

}
HttpListener listener;
private string _text = &quot;&quot;;

/// <summary>
/// ドロップされた時
/// </summary>
/// <param name=&quot;sender&quot;></param>
/// <param name=&quot;e&quot;></param>
private void Form1_DragDrop(object sender, DragEventArgs e)
{
    var text = &quot;&quot;;
    var obj = e.Data;
    foreach (var fmt in obj.GetFormats())
    {
        Debug.WriteLine( fmt );
        if (fmt == &quot;text/uri-list&quot;)
        {
            var sr = (MemoryStream)obj.GetData(&quot;text/uri-list&quot;);
            text = Encoding.Unicode.GetString(sr.ToArray());
            break;
        }
    }
    textBox1.Text = text;
    _text = text;
}

private void Form1_DragEnter(object sender, DragEventArgs e)
{
    e.Effect = DragDropEffects.All;
}

簡易サーバーは HttpListener で作れば ok です。今回はポート番号を 8090 にして待ちにします。URLはFirefox からドラッグ&ドロップします。何故かIE10の場合はできないのですが…まあ、自分専用なのでFirefoxで。これは後で調査。

■Surface RT 側のクライアント

image

自動的に取ってくるのがいいのですが、ひとまず、Get ボタンで URL を取得、その後 IE10 で開くという処理を続けてやります。

private async void GetClick(object sender, RoutedEventArgs e)
{
    string url = "http://mars:8090/url";
    HttpClient cl = new HttpClient();
    var res = await cl.GetAsync(new Uri(url));
    var text = await res.Content.ReadAsStringAsync();
    text1.Text = text;
    // 起動
    await Windows.System.Launcher.LaunchUriAsync(new Uri(text));
}

■サーバーの設定

実は Winodows 8 では、ポートの制限が厳しくて、単純に HttpListener を作っただけでは動きません。管理者のコマンドラインから、次のコマンドを実行します。

 netsh http del urlacl url=http://*:8090/ -user=masuda 

Community Open Day 2012 の補足その1 – Moonmile Solutions Blog
Community Open Day 2012 の補足その2 – Moonmile Solutions Blog
に、netsh の使い方が書いてあります。

あとは、ファイアーウォールで、8090 のポートを開けることです。ポート絡みがややこしいので、本格的にツールにするとしたらインストーラが必須ですね。

■で、何につかうのか?

iSteve from Justin Long, Jorge Garcia, James_Urbaniak, Michaela Watkins, Steve Tom, John Ross Bowie, Paul Rust, Ryan Perez, Juzo Yoshida, Brian Huskey, Art Evans, jill_donnelly, Anthony Gioe, Ally Hord, iSteve, Funny Or Die, Charles Ingram, NickCorirossi, Joe Farrell, and Katy Walker を Surface に送ってみたかったんですよ…って、動かしてみたら、ああ、Surface RT の IE10 だと Flash が動かないタイプな模様 orz 、結局デスクトップPCで閲覧

■サンプルソース

サンプルソースはこちら。適当にホスト名とかポート番号とかを変えて使ってください。

カテゴリー: WinRT | [WinRT] デスクトップで閲覧しているURLをSurface RTに送る はコメントを受け付けていません

Frameworks Round 2 に ASP.NET系を含めてみたい

@neuecc さんのツイートの「Cakeは…」から辿った Frameworks Round 2 – TechEmpower Blog を眺めてみていくつかメモ。

http://www.techempower.com/blog/images/article/framework-benchmarks-round2/json-i7.png

正直「CakePHPがこんなに下位≒遅いなんて信じられない~」かつフレームワーク選定を考え直さないといけないなと思いつつ、が調べていった発端なので、ちょっと視点がずれているかもしれませんが。まあ、個人の感想ということで。

ちなみに、ベンチマークのソースコードは TechEmpower/FrameworkBenchmarks · GitHub でダウンロードできます。Issues · TechEmpower/FrameworkBenchmarks · GitHub を見ると、結構な量のコメントがあるので「釣り」としてうまく機能しているかなと。それぞれ、自分の使っているフレームワークを心理的に擁護したいので、続々とコメントが集まって来ています。そういう自分も釣られた一人。ただ、こういう絨毯爆撃的なベンチマークはあまりないので(Oracle にはベンチマークをしちゃダメという契約条項もあるし)さっくりと比較記事的に面白いし、相対的に色々なコードを眺めるきっかけになります。netty は前から知っていたのですが、こういう風に比較をすると Java コードであっても無視できないですよね~、とか。

では、30分ぐらいでざっと書き下します。以下、主に Database access test (multiple queries) を見て比較しています。

■ASP.NET 系が入っていない問題

意図的…というよりも、Amazon EC2 上と Ubuntu 上になるので、.NET 系が入っていません。mono で動かせば?というのがコメントとかにありましたが、ここはやっぱり IIS 上で再実験してみたいところです。気になるポイントは、

  • netty 風に .net で非同期/単体サーバープログラムを作った場合どうなるのか?
  • ASP.NET MVC がどの位置になるのか?
  • ASP.NET Web API がどの位置になるのか?

リクエスト数の絶対値ではなくて、相対値を調べることになるので、PHP まわり、Ruby まわりも IIS 上で動かしてみる必要がありかと。xampp をインストールして、べたな状態で動かすのもありですね。java のほうは詳しくないので、Spring とか Hivernate とか動けばokかと。

■servlet-raw と php-raw がほぼ同じ

ソースコードを見ると php-raw と php の違いは、直接 PDO を使うか、ActiveRecord というライブラリを使うかの違いですかね?(ActiveRecordをよく知らない)。ActiveRecord は MVC っぽい作りなので、べたで作れば PDO を使うし(Wordpress は mysql_query を使うから遅いという話もあるし)ってことで、java の servlet と同じスピードが出るのであれば、さっくりと PHP で組むのもありかな?と思ったり。乱暴ですが。

ただし、フレームワークベンチな訳で、spring が servlet-raw よりもあまり遅くなっていないのはいいですよね。

■コネクションプーリングの問題

設定をみると CakePHP のコネクションプーリング?(persistent)の設定がoffになっているし、そもそも PHP って MySQL に対してプーリングができるのかどうかが怪しいし、そういう点ではコンパイル系の Java のほうがマルチコネクションに対しては断然有利です。今回のベンチマークのように、小さいクエリを何度もクライアントから発行する場合は、サーブレットで DB に接続する時間がほとんどを占めてしまうので、java と php では大きな差が出る可能が…と言いつつ、servlet-raw と php-raw の差があまりないので、そうでもないのかも。このあたりは自分で再実験をしてみたいところです。

■MVC の問題

MVC パターンを噛ますと、当然クラスロードやらなんやらで遅くなっていしまうのが当然で、このあたりは、CakePHP、Rails は不利ですよね。struts が入っていないのは意図的?最近は使われない?

なので、この中に ASP.NET MVC、ASP.NET Web API がどの位置になるのかが興味あるところです。MVC を入れるのは、瞬間的なパフォーマンスよりも、継続的プログラミングのパフォーマンスや、ローンチのパフォーマンスを上げたいってところが主なので、そこで実行時のパフォーマンスとのトレードオフがあっても然り。

■Apache と IIS の問題

Ubuntu なので、Apache を使っていますが、Windows Server にすれば、IIS+PHP+MySQL とか、IIS+PHP+SQL Serverとか、IIS+ASP.NET+SQL Server とか諸々の組み合わせがでてきます。フレームワークの比較からは外れますが、Windows Server 上で動かした場合(Azure 上で動かした場合)は、このフレームワークランキングって変わるのか?ってのが興味あるところです。

# ざっくりと、ASP.NET Web API はチェックしたい。

カテゴリー: 開発 | 3件のコメント

MySQLでMySqlBulkLoaderのスピードをHDD/SSDで比較する

SSDにするとBlukcopyは5倍ぐらい早くなる – Moonmile Solutions BlogMySQLでHDD/SSDのアクセススピードを比較する – Moonmile Solutions Blog の続きです。@h141gm さんから、MySqlBulkLoader もあるよ、ということなので再実験。さすがに、insert の連続では SQL Server との比較が無理があるし、insert の連続が SSD の処理に追い付いているかどうかもあやしいので、ちょっと仕切り直します。

# my.ini の値は、xampp の吊るしのまま使っています。ひとまず既製品状態でどのくらいの差がでるのかな?ってことで。チューニングするとどの位なのか?ってのも興味あるところなのですが「チューニングしなくても、SSD を換装すれば「手軽に」早くなる、ってのが理想的なのです。

例によって、100万件のアクセス生ログを読み込せます。

■MySqlBulkLoader で insert する

SSD の BulkLoader で、11.8 sec

image

image

HDD で 26.8 sec

image

image

SSD のほうが HDD よりも 2.5 倍ぐらい早くなっています。

BulkCopy/BulkLoader SSD HDD
SQL Server 7.8 sec 32.1 sec
MySQL 11.8 sec 26.8 sec

SQL Server の BulkCopy は、メモリ上の DataTable から一気に突っ込むので、ファイルを解析しながロードする MySQL の BulkLoader よりも早いのは当然…なのですが、ええ、HDD のほうが逆転しているけど無視で(苦笑)。ロードするファイル自体は SSD に置いてあるので、このファイルが HDD 上にあると MySQL の BulkLoader のほうが遅くなる可能性があります。この計測からいけば、単純に HDD から SSD に切り替えただけでも、2.5 倍から 4 倍ぐらいの効果がありますね、ってことが分かります。

■500万件のデータから SELECT する

SQL Server のデータベースファイルを SSD に移す – Moonmile Solutions Blog と似たようなクエリを使って計測します。

初回の SELECT が、SSD で 5.1 sec、HDD が 7.9 sec

imageimage

2回目以降はキャッシュが効くのかと思っていたら、SSD で 5.0 sec、HDD で 7.9 sec と変わりません。このあたりはチューニングで変わるのかもしれません。

imageimage

SSD初回 SSD二回目 HDD初回 HDD2回目
SQL Server 4.6 sec 0.4 sec 15.1 sec 0.4 sec
MySQL 5.1 sec 5.1 sec 7.9 sec 7.9 sec

使用メモリを見ると、SQL Server は2回目のときに 4GB 程度取っていますが、MySQL の場合は 36 MB 程度と謙虚です。がっつりメモリを割り当ててやれば、MySQL の場合も超早になるのかなと。ただし、SQL Server + HDD の組み合わせが遅すぎですよね…MySQL が早いのかもしれませんが。

この結果を見ると、SELECT の場合は、HDD から SSD に換装してもあまりメリットがないかな、って感じもします。この場合は、単純なアクセスログでワンテーブルの検索でしかないので、複雑な join をしたときにはどうか分かりませんが、大量データ&単純な全検索のパターンだと、SELECT 時の恩恵はあまりないかもしれません。ええと、チューニングすれば別のような気もしますが。

■実験コードの抜粋

MySqlBulkLoader を利用

void GoBulkLoad(string CNSTR)
{
    MySqlConnection cn = new MySqlConnection(CNSTR);
    MySqlBulkLoader bl = new MySqlBulkLoader(cn);
    bl.TableName = "logs";
    bl.FieldTerminator = "t";  // タブ区切り
    bl.LineTerminator = "n";   // 改行
    bl.FileName = @"D:sitelogsout.csv";

    DateTime start = DateTime.Now;

    cn.Open();
    bl.Load();
    cn.Clone();

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

MySqlCommand で検索

void GoSelect(string CNSTR)
{
    var ip = textBox1.Text;
    var cn = new MySqlConnection(CNSTR);
    var cmd = new MySqlCommand(
        "select count(*) from logs where ip = @ip", cn);
    cmd.Parameters.Add(new MySqlParameter("@ip", ip));
    DateTime start = DateTime.Now;
    cn.Open();
    object cnt = cmd.ExecuteScalar();
    cn.Clone();

    DateTime end = DateTime.Now;
    label4.Text = string.Format("検索結果 {0}件 {1:#.0} sec", cnt,
        ((TimeSpan)(end - start)).TotalSeconds);
}
カテゴリー: MySQL, パフォーマンス | MySQLでMySqlBulkLoaderのスピードをHDD/SSDで比較する はコメントを受け付けていません

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(&quot;INSERT INTO logs  values ( @dt, @code, @ip, @req, @url )&quot;, cn );
    cmd.Parameters.Add(  new MySqlParameter(&quot;@dt&quot;,  MySqlDbType.String ));
    cmd.Parameters.Add(  new MySqlParameter(&quot;@code&quot;,  MySqlDbType.String ));
    cmd.Parameters.Add(  new MySqlParameter(&quot;@ip&quot;,  MySqlDbType.String ));
    cmd.Parameters.Add(  new MySqlParameter(&quot;@req&quot;,  MySqlDbType.String ));
    cmd.Parameters.Add(  new MySqlParameter(&quot;@url&quot;,  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[&quot;@dt&quot;].Value = row[&quot;dt&quot;];
                cmd.Parameters[&quot;@code&quot;].Value = row[&quot;code&quot;];
                cmd.Parameters[&quot;@ip&quot;].Value = row[&quot;ip&quot;];
                cmd.Parameters[&quot;@req&quot;].Value = row[&quot;req&quot;];
                cmd.Parameters[&quot;@url&quot;].Value = row[&quot;url&quot;];
                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(&quot;dt&quot;, typeof(string)));
    dt.Columns.Add(new DataColumn(&quot;code&quot;, typeof(string)));
    dt.Columns.Add(new DataColumn(&quot;ip&quot;, typeof(string)));
    dt.Columns.Add(new DataColumn(&quot;req&quot;, typeof(string)));
    dt.Columns.Add(new DataColumn(&quot;url&quot;, typeof(string)));

    _completed = false;
    await Task.Factory.StartNew(
        () =>
        {
            var sr = System.IO.File.OpenText(@&quot;D:sitelogsout3.csv&quot;);
            _count = 0;
            while (sr.EndOfStream == false)
            {
                string line = sr.ReadLine();
                string[] v = line.Split(new string[] { &quot;t&quot; }, StringSplitOptions.None);
                DataRow row = dt.NewRow();
                dt.Rows.Add(row);
                row[&quot;dt&quot;] = v[0];
                row[&quot;code&quot;] = v[1];
                row[&quot;ip&quot;] = v[2];
                row[&quot;req&quot;] = v[3];
                row[&quot;url&quot;] = 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(&quot;{0} 件読み込み中&quot;, _count)));
        }
        label2.Invoke((MethodInvoker)(() => label2.Text =
            string.Format(&quot;{0} 件読み込み完了&quot;, _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 を動かす方法 はコメントを受け付けていません