RE: BUILD での注目点
ネタ元: BUILD での注目点 « ++C++; // 未確認飛行 C ブログ
BUILD 面白そう (^o^)
早くも、Windows 8 は Windows 7 よりも良いものになりそうな予感。
ということで、以下、Iネタ元読んでて思ったことなどなど。
ISO イメージのマウント
ISO イメージのマウントは、Windows 7 時点でそれっぽい API が定義されていました。
この API は、API 引数でイメージの種類(=.iso, .vhd など)を指定する仕様でしたが、Windows 7/Windows Server 2008 R2 でちょっと試した範囲では、.iso イメージマウントに関しては期待通りの動作をしてくれませんでした。
Windows 7/Windows Server 2008 R2 時点では「API 的には整備されているけど、実際にはその背後でうごめくプロバイダが提供されていなくて、結局のところ利用不可」てことだった模様。
ちなみに、Widnows 8 での ISO イメージマウントがこの API によって可能となるのかなどは現時点では不明(だよね?)
Protogon ファイルシステム
ファイルシステムがより多くのメタ情報を持つこと自体はいいことなんだけど、相互運用どーするかもちゃんと考えてねと。
かつて、WinFS のデモが盛んに行わていた時代に、演者に「マシン間でファイルをコピーしたらメタ情報は落ちちゃうの?」と何度か質問をしたことがあるけど、結局、真正面から答えてくれた人はひとりもいなかった。たまたまかもしれんけど ;-p
Windows 7 の「ライブラリ」は大好きな機能だけど、これも結構制約が多い(=Linux ベースの NAS のフォルダなんかは事実上追加できなかったりする)のが難点。
あまり先取りしすぎないように気をつけてください。
Windows Live ID と、クラウドを使った設定の同期
Windows Live Mesh で一部できてるけど、これをもっと推し進める感じかな?
AD と共存できるといいんだけど…
Trident
IE のレンダリングエンジンは IE4 あたりからずーっと Trident って名前だったはず。
Visual Studio 2012
公式にはまだ製品名決まってないはず。
でも、「製品名に 2013 を冠するはずはない」と信じてるwので、2012 年(年度?)中にどばっと、いろいろ製品が出てくるはず。
[C#] LINQ to SQL の実行速度を3倍に加速するっ!
どーも最近、ダメな子扱いされがちな LINQ to SQL ですが、クエリ結果を(ほぼ)透過的にキャッシュすることで実行速度を約3倍に加速してみました。
使い方はひじょーにカンタン。
通常
var connectionString = Properties.Settings.Default.Database1ConnectionString;
using (var db = new DataClasses1DataContext(connectionString))
{
var array = db.Products.Where(__ => __.Price > 500).OrderBy(_ => _.Price).Take(200).ToArray();
}
みたいに書くところを
var connectionString = Properties.Settings.Default.Database1ConnectionString;
using (var connection = new Mjollnir.Data.SqlClient.SqlConnection(connectionString, new MemoryCache()))
using (var db = new DataClasses1DataContext(connection))
{
var array = db.Products.Where(__ => __.Price > 500).OrderBy(_ => _.Price).Take(200).ToArray();
}
のように、データベース接続を別クラスに差し替えるだけ。
実際には少しばかりの準備(=プロジェクトに上記 SqlConnection の代替えクラスおよび SqlCommand の代替えクラス、キャッシュ実装クラスを追加)は必要だけど、クエリの記述や結果の扱いに変更を加えないで済むのがミソ。
これでどれくらいのパフォーマンス向上があるかとゆーと…
| Id | int |
| Name | nvarchar(100) |
| Price | int |
とゆー構成で1000項目が登録されたテーブルに対して
private static IEnumerableExecuteQuery(DataClasses1DataContext db, int queries) { var list = new List (); for (int i = 0; i < queries; i++) { list.Add(db.Products.Where(__ => __.Price > 500).OrderBy(_ => _.Price).Take(200).ToArray()); } return list; }
とゆータスク(queries = 10 に設定)を100件連続して実行した場合の実行時間は以下のとおり。
| 1回目 | 2回目 | 3回目 | 4回目 | 5回目 | |
| 通常の LINQ to SQL | 5.453s | 3.693s | 2.811s | 2.84s | 2.827s |
| LINQ to SQL + サンプルキャッシュ実装 | 0.942s | 0.909s | 0.906s | 0.909s | 0.906s |
てなカンジ。
概ね3倍のパフォーマンス向上が見られるのでありました。
↑と同じ設定のタスクを ThreadPool を使って同時並行に実行すると
| 1回目 | 2回目 | 3回目 | 4回目 | 5回目 | |
| 通常の LINQ to SQL | 0.964s | 0.972s | 0.976s | 1.004s | 0.987s |
| LINQ to SQL + サンプルキャッシュ実装 | 0.277s | 0.271s | 0.27s | 0.288s | 0.269s |
とゆー結果。あれ?思ったほど伸びてない (^^;
実行時間そのものはマルチスレッド化によって短縮されているものの、「約3倍のパフォーマンス向上」てとこには変化ナシ…
サンプルではローカルのファイルアタッチ DB を相手にしているので、そのせいかな?
ネットワーク接続の DB なら、キャッシュヒットした時の利益はひとしおなので、もうちょっと差が出るハズ。
ところで、実は「LINQ to SQL のパフォーマンスを向上する」のであれば
- CompiledQuery を利用する
- 結果セットをキャッシュする
のが定番コース。
なのに、なんでわざわざこんな風変わりなアプローチをしているのかとゆーと…
↑で挙げた代表的な2つの手法には
- クエリ実行のコードの書き換えが必要(=透過的でない)
- SqlDependency によるキャッシュエントリの効率的なエクスパイアを実行しづらい
という短所があるから。
前者は(必要なら)我慢するとしても、後者はもうちょっとどーにかしたいところ。
で、今回採用した「LINQ to SQL の DataContext に、DbConnection.CreateCommand() で DbCommand.ExecuteReader メソッドの処理を外部に移譲する DbCommand 派生クラスインスタンスを返す DbConnection 派生クラスインスタンスを渡す(長っ)」という手法なら
- DataContext を new する時のコードをホンの少し書き換えるだけ
- 結果セットのキャッシュを SqlCommand 相当のクラス内で行うので、SqlDependency を容易に扱える
となるワケ。(SqlDependency を使ったキャッシュ実装はまだ作ってないけど (^^;)
あと、LINQ to SQL のクエリ結果と違って、この層なら結果セットに含まれる値の型はごくシンプルなモノばかりなので
LINQ to SQL のクエリ結果を分散ストレージにキャッシュする
なんてことも理論的には可能だったりする。
てか、実のところ、今回の投稿はそれを検討するため下地だったりなんかして (^^;
なお、サンプルプロジェクトは VS2010 で作ったけど、ターゲットは .NET3.5SP1 なので、ソースファイルを抜き出してプロジェクトを再構成すれば VS2008 でも動作するはず。
PowerShell でジェネリックメソッドを呼び出す
PowerShell の長所の一つとして「.NET Framework との親和性が高い」ことが挙げられるわけですが、いかんせんジェネリックメソッドの呼び出しはちょとシンドイ。
というわけで、ジェネリックメソッド呼び出しのメンドクサさを隠蔽すべく
Param(
[Parameter(Mandatory=$True, HelpMessage="ジェネリックメソッドを公開する型を指定します。")]
[ValidateNotNull()]
[Type] $Type,
[Parameter(Mandatory=$True, HelpMessage="ジェネリックメソッドの名前を指定します。")]
[ValidateNotNullOrEmpty()]
[String] $MethodName,
[Parameter(Mandatory=$True, HelpMessage="ジェネリック型パラメータに与える Type 型の配列を指定します。")]
[ValidateNotNullOrEmpty()]
[Type[]] $GenericArgumentTypes,
[Parameter(HelpMessage="ジェネリックメソッド呼び出しの対象となるオブジェクトインスタンスを指定します。")]
[Object] $Object = $Null,
[Parameter(HelpMessage="ジェネリックメソッド呼び出しの引数となる Object 型の配列を指定します。")]
[ValidateNotNull()]
[Object[]] $ArgumentList = @())
Trap { break }
$MethodInfo = $Type.GetMethods() |
Where-Object {$_.Name -eq $MethodName} |
Where-Object {$_.IsGenericMethod} |
Where-Object {$MethodInfo.GetGenericArguments().Length -eq $GenericArgumentTypes.Length} |
Select-Object -First 1
$GenericMethodInfo = $MethodInfo.MakeGenericMethod($GenericArgumentTypes)
$GenericMethodInfo.Invoke($Object, $ArgumentList)
なんてスクリプトを書いてみた。
使い方は
Invoke-GenericMethod.ps1 -Type Linq.Enumerable -MethodName Repeat -GenericArgumentTypes Int32 -ArgumentList @(9,4)
みたいな感じ。
これは、C# の
Enumerable.Repeat<int>(9, 4);
に相当。
ちょっと引数が多いけど、汎用的に仕上げたかったのでこんなモンでしょう。
必要に応じて
Function EnumerableRepeat([Int32] $Element, [Int32] $Count)
{
Invoke-GenericMethod.ps1 -Type Linq.Enumerable -MethodName Repeat -GenericArgumentTypes Int32 -ArgumentList @(9,4)
}
みたいなラッパ関数を書くってのも手。
「RSS 配信」をしばらく休止します
Web 移転にともない、http://hidori.jp/rss/ でサービスしている開発系掲示板の「RSS 配信」がしばらくの間、全面的に停止します。
ホスティングサーバ上で動作するように改訂が必要なので、再開にはかなり時間がかかりそうです。
# RSS のリクエスト URL は維持する方向で努力します。
Web サーバーを移転しました
ながらく自宅サーバーで hidori.jp ドメインの Web サーバーを運用してきましたが、データジャパンが運営するホスティングサービス ExpressWeb に移転しました。
まだ WordPress を入れただけなので、ぼちぼち整備していきたいと思います。
文字列の中から数字だけ取り出すには?
ネタ元: 文字列の中から数字だけ取り出すには?
文字列に含まれた複数の数字列を取り出して連結。
もっと簡潔に…書けるかなぁ?
using System;
using System.Linq;
using System.Text.RegularExpressions;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
string text = "あ1いう3え4お56789";
Console.WriteLine(
string.Concat(Regex.Matches(text, @"\d+").Cast().Select(_ => _.Value).ToArray()));
}
}
}
追記: 2010-06-04
Twitter でいくつかフィードバックを貰ったので、再考。
正規表現を使ってないので、この系統の方が性能的には有利なはず。
でも、char[] から string を得るのに string(char []) を使っているところが、ワンライナー的には許せないw
using System;
using System.Linq;
using System.Text.RegularExpressions;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
string text = "あ1いう3え4お56789";
Console.WriteLine(
new string(text.Where(_ => char.IsDigit(_)).ToArray()));
}
}
}
さらに追記: 2010-06-04
お題を消化するだけならコレが最強w
^ による否定をすっかり忘れてたヨ…
あーんど、なんでもかんでも LINQ ろうと思ってはいけないね (^^;
using System;
using System.Text.RegularExpressions;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
string text = "あ1いう3え4お56789";
Console.WriteLine(
Regex.Replace(text, @"[^\d]", string.Empty));
}
}
}
0 から 1000 までに含まれる ‘0’ を数える
ネタ元: gist: 415551 – from http://d.hatena.ne.jp/os0x/20081115/1226770265- GitHub
Sum() しない版。
足し算で「個数を求める」のではなく、「数える」という点を強調したつもり。
あと、ネストをするとラムダ式の引数の名前考えるのがめんどくさい (^^; ので、SelectMany() を使って、早い段階でフラットな IEnumerable に変換してしまっているのもミソ。
using System;
using System.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(
Enumerable.Range(0, 1001).SelectMany(_ => _.ToString()).Count(_ => _ == '0'));
}
}
}
勝手に競演
ネタ元: 夢の競演みたび
そのままだと面白くないので、複数除外できるようにしてみた。
簡素さを優先するとこんな感じ。excludes を何度も舐めるのが美しくないけど。
result を何度も列挙するような場合、result.ToArray() すればいいよね。
1回しか回さないなら、これでおk。
using System.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var source = new[]
{
new { Name = "しゅうたん", Type = "アメショ" },
new { Name = "ろり", Type = "アメショ" },
new { Name = "みずきちゃん", Type = "スコティ" },
new { Name = "マグさん", Type = "ほげ" },
new { Name = "?", Type = "もげ" },
};
var excludes = new[] { "ほげ", "もげ" };
var result = source.Where(_ => !excludes.Contains(_.Type));
foreach (var item in result)
{
System.Console.Out.WriteLine("Name = {0}, Type = {1}", item.Name, item.Type);
}
}
}
}
【緩募】イベントのエレガントな発火
Name プロパティの変更を通知するイベントの場合、イベント発火は通常
// Name プロパティが変更されたことを通知します。
public event EventHandler NameChanged;
// NameChanged イベントを発火します。
protected void OnNameChanged()
{
if (this.NameChanged != null)
{
this.NameChanged(this, new EventArgs());
}
}
なんてしておいて
this.OnNameChanged(); // NameChanged イベントを発火
とするのがお定まりなワケですが、この OnNameChanged() をもうちっとばかり美しく書きたいわけデス。
とりあえず
// 指定されたイベントを発火します。
public static void Fire(this EventHandler eventHandler, object sender)
{
if (eventHandler != null)
{
eventHandler(sender, new System.EventArgs());
}
}
// 指定されたイベントを発火します。
public static void Fire<TEventArgs>(this EventHandler<TEventArgs> eventHandler, object sender, TEventArgs eventArgs) where TEventArgs : EventArgs
{
if (eventHandler != null)
{
eventHandler(sender, eventArgs);
}
}
てな拡張メソッドを用意して
// NameChanged イベントを発火します。
protected void OnNameChanged()
{
this.NameChanged.Fire(this);
}
なんて感じに書けるようにはしてみました。
これだと、sealed なクラスでは
public string Name
{
get { return this.name; }
set { this.name = value; this.NameChanged.Fire(this); }
}
てな感じで OnXXX() とオサラバすることもできて、なかなかイイ感じです。
んが、これだと EventHandler と EventHandler<TEventArgs> にしか対応出来ないところが微妙デス。
このままでは、例えば PropertyChanged イベントみたいなイベントデリゲートが定義済みのイベントには通用しなかったりするわけです。
PropertyChanged イベントはマイブーム(笑)なので、特別に
// 指定されたイベントを発火します。
public static void Fire(this PropertyChangedEventHandler eventHandler, object sender, PropertyChangedEventArgs eventArgs)
{
if (eventHandler != null)
{
eventHandler(sender, eventArgs);
}
}
てのも書いちゃったけど、XXXEventHandler が登場する度に専用の Fire() を書くなんてのはやってらません ;-p
なんかいいアイデア無いでしょうか?
XBOX360: Borderlands
久々に XBOX360 の新作をやってみた。
今回やってみたのはコレ。
Borderlands
http://www.xbox.com/ja-JP/games/b/borderlands/
「RPG と FPS の融合」という煽り文句に期待と不安 (^^; を抱きつつ起動。
海外タイトルの日本語版ということで、もっとバタ臭い絵柄かと思ってたけど、意外とあっさりめな感じで好感触。
「あっち系」のテイストは残したまま、日本のアニメっぽい雰囲気もありつつで、ざっくり言うと海外版の「AKIRA」みたいな感じかな?
ゲームの世界観は「マッドマックス」や「北斗の拳」系の「荒野+パンクな悪者」という組み合わせ。(+ほんの少しサイバー?)
とりあえずチュートリアル兼の1面だけやってみたけど、最初、何をどーすればいいかよく分からなかった (^^;
行き先はパートナーのロボットが教えてくれるし、コントローラの操作もヘルプがあるんだけど、「何が拾えるのか」とか「どこに出入口があるのか」なんてのが分かりにくいと感じた。日本製のヌルイ RPG とかやってる報い???
確定申告も終わったことだし、しばらくやりこんでみよっと