Hatena::ブログ(Diary)

当面C#と.NETな記録 このページをアンテナに追加 RSSフィード

2014/8/15 (金)

2012/4/20 (金)

[] C# 5 での互換性のない変更  C# 5 での互換性のない変更 - 当面C#と.NETな記録 を含むブックマーク  C# 5 での互換性のない変更 - 当面C#と.NETな記録 のブックマークコメント

C#5 では、ループ変数とラムダ式の嫌な問題を一つ直すようです。

var values = new List<int>() { 0, 1, 2 };
var funcs = new List<Func<int>>();

foreach ( var v in values )
    funcs.Add( () => v );
foreach ( var f in funcs )
    Console.WriteLine( f() );

このコードを実行すると C#4 までは予想に反して「2 2 2」ですが、C#5 からは「0 1 2」となります。Windows 8 CP 上の Visual Studio 11 で試した結果です。C# の「破壊的」仕様変更であり、後方互換性がなくなります。

これまでも、この問題には簡単な回避策があり、ループ中で v をいったん var v2 = v; と別の変数に入れてラムダ式から v2 を参照すれば、まともに動きます。しかし、これまでの動作は誰も得しないので仕様を変更してまで修正するようです。

foreach はコンパイラによって while を使ったコードに展開されますが、このときループの外で変数を定義していたのを、ループの中で定義することで修正します。Eric Lippert さんの blog から引用します。

{
    IEnumerator<int> e = ((IEnumerable<int>)values).GetEnumerator();
    try
    {
      int m; // OUTSIDE THE ACTUAL LOOP
      while(e.MoveNext())
      {
        m = (int)(int)e.Current;
        funcs.Add(()=>m);
      }
    }
    finally
    {
      if (e != null) ((IDisposable)e).Dispose();
    }
}

この int m; を while の中へ。

    try
    {
      while(e.MoveNext())
      {
        int m; // INSIDE
        m = (int)(int)e.Current;
        funcs.Add(()=>m);
      }

従来は一つだけの変数の寿命が伸びていたので最後の値が見えていました。これからは、ループのたびに変数が作られ、それぞれの寿命が伸びることで解決します。

しかし! for は変更なしです。

var funcs2 = new List<Func<int>>();

for ( int i = 0; i < 3; i++ )
    funcs2.Add( () => i );
foreach ( var f in funcs2 )
    Console.WriteLine( f() );

この結果は「3 3 3」で変わりません(「2 2 2」でもありませんw)。


Eric Lippert さんが挙げる foreach の変更の悪い点。

  1. 互換性がなくなる破壊的変更であること。
  2. foreach の構文に矛盾しているように見えること。foreach ( int x in M() ) の右側にある M() より、左にある int x が内側にあるような感じ。左から右という一般的な規則に反する。
  3. foreach と for で一貫性がなくなる。
  4. 簡単な回避策があるのに破壊的変更は必要?

それでも変更するようです。


参考、および引用元:


おまけ。Eric さんの blog の最後の方にある pros or cons (pros and cons) とは、アメリカの子供が学校で習う考える訓練方法で、紙の真ん中に線をひき、左と右に良い点悪い点を書き出して考える方法だそうです。真ん中辺りの画像が参考になります。

2011/4/23 (土)

[] iPhone Tracker for Windows をつくりました  iPhone Tracker for Windows をつくりました - 当面C#と.NETな記録 を含むブックマーク  iPhone Tracker for Windows をつくりました - 当面C#と.NETな記録 のブックマークコメント

f:id:siokoshou:20110423233952j:image

http://sites.google.com/site/siokoshou/

Windows 7 x64 でのみ動作確認済みです。.NET3.5 入り XP でも動きます。

↓のMac版とだいたい同じモノのつもりです。でも、Mac持ってないし本家のモノを動かしたわけではないので本当に同じかわかりません。

http://petewarden.github.com/iPhoneTracker/

本家同様、日時は週単位に丸め、緯度経度もある程度丸めています。

そもそもの iPhone Tracker についてはこちらをどうぞ。

http://japanese.engadget.com/2011/04/20/ios-4-pc/


追記

  • ソース公開しました。Visual Studioのプロジェクトです。不要と思われるファイルを消してあります。不足があればすいません。
  • Ver1.2 - 4/24 19:00ころ Ver1.2に更新しました。
    • いくつかのバグ修正。
  • Ver1.1 - 4/24 16:00ころ Ver1.1に更新しました。
    • Wifiロケーションも表示するようにしました。
    • 重複した位置情報のまとめ方を修正しました。
    • これによってデータ量が減り、だいぶ速くなりました。
  • Ver1.0 - 4/23 公開しました。

iponipon 2011/04/24 11:41 win7 bitですが、lodingの所で応答なしになって止まります。
.NET4.0を入れています。

siokoshousiokoshou 2011/04/24 12:42 iponさん
おそらく大量の位置データが記録されているためです。しばらく待ってみてください。
位置情報を地図上にプロットする処理はJavaScriptによって動いているのでかなり遅いです。

ueponuepon 2011/04/24 13:13 WinXP Pro(SP3) 32bitですがちゃんと動いてます。拡大縮小時は時間かかりますが、それ以外は今のところ問題ありません。

siokoshousiokoshou 2011/04/24 13:35 ueponさん
ありがとうございます。XPでも動いてよかったです。
拡大縮小はWin7でも遅いです(^^;

winwin 2011/06/22 04:22 windows7ですが、起動すると動作を停止しましたとなります。

siokoshousiokoshou 2011/07/16 14:34 winさん、返事が遅くなりすみません。
iOS4.3.3で位置情報がPCにバックアップされなくなりました。
詳細は http://japanese.engadget.com/2011/05/04/ios-4-3-3/

このため、動作が停止しましたと表示されるかもしれません。
iPhone Tracker はすでにその役割を終えたと思っていましたが、そのうち、エラーがわかりやすく表示されるように修正したバージョンアップを作るかもしれません。

2009/12/19 (土)

[] 除算と剰余の整数オーバーフロー  除算と剰余の整数オーバーフロー - 当面C#と.NETな記録 を含むブックマーク  除算と剰余の整数オーバーフロー - 当面C#と.NETな記録 のブックマークコメント

プログラムでは整数の四則演算はよくよく注意しないと足をすくわれることがあります。

整数と呼んでるものが普通と違って範囲があって循環しているためです。最大値と最小値の絶対値が 1 ズレているのもいや〜な問題の元になります。

この 1 ズレのため除算で整数オーバーフローが発生します。除算でですよ。

int の最小値を -1 で割ったときに結果が表現できないためです。除算と剰余ではただこの 1 ケースのみオーバーフローが起きます。

このケースは仕様書にちゃんと書いてあります。仕様書によると checked では例外スロー。unchecked では「unchecked コンテキストでは、System.ArithmeticException (またはコンテキストでのサブクラス) がスローされるか、または左のオペランドを結果値としてオーバーフローを報告しないかは、実装で定義されます。」実装依存だそうです。では Visual Studio 2008 SP1 で試してみます。

「int x = int.MinValue / -1;」と書くとコンパイルエラーになります。下のように書くとコンパイルは通ります。おバカさんめ。

static void Test1()
{
    int m = int.MinValue;
    int n = m / -1; // OverflowException 発生
    Console.WriteLine( n );
}

実行すると unchecked なのに OverflowException が飛んできました。x86/x64 Debug/Release ぜーんぶ全部です。checked も当然同じです。

0 で割り算しようとしてしまうのは当然気を付けますが、-1 も実は注意が必要ということですね。


続いて剰余。こっちはクレイジーです。

「int x = int.MinValue % -1;」と書くと x は正常に 0 になります

ところが

static void Test2()
{
    int m = int.MinValue;
    int n = m % -1; // OverflowException 発生!!
    Console.WriteLine( n );
}

これを実行すると除算同様 OverflowException が飛んできます。ひどい。コンパイル時と実行時で違うんですね。

checked も x86/x64 Debug/Release 全部 OverflowException です。

仕様書によると「左オペランドが int または long の最小値で右オペランドが -1 の場合は System.OverflowException がスローされます。x / y が例外をスローしない場合に x % y が例外をスローすることはありません。」だそうです。x / y が例外をスローするなら x % y が例外をスローする、とは書いてませんが MS のコンパイラはそういう動きをしました。これを書いてないのは高速化のために実装の幅を残すためでしょうね。

そもそも 0 でいいのに。CPU では除算と剰余が一体なので、除算でオーバーフローが起きたら剰余もその結果に従うということのようです。x86 では CPU が例外を投げるようですが、x64 では 32bit 演算なのに結果は 64bit 幅なので、しょうがなく(?) JIT 後の機械語に int.MinValue % -1 かどうかチェックするコードが生成されていました。明らかにそうじゃない場合はチェックコードは生成されません。わざわざチェックコードを生成するなら x86 にチェックコードを加えて 0 を返せばよかったのに。

まあ、マイナス割るマイナスって一体何だかわかりませんが、こんなことがあるので注意が必要ですよというお話でした。

2009/10/30 (金)

[] .NET4.0 の並列処理を試してみた その3 : サーバー GC  .NET4.0 の並列処理を試してみた その3 : サーバー GC - 当面C#と.NETな記録 を含むブックマーク  .NET4.0 の並列処理を試してみた その3 : サーバー GC - 当面C#と.NETな記録 のブックマークコメント

id:siokoshou:20090717id:siokoshou:20090721id:siokoshou:20090722 に続く TPL の記事。ベータ2の改良点がパラレルチームの blog に投稿されています。

でも、今回はそんなのがどうでもよくなるほど驚いたネタ。

ベータ2で7月に試したコードを実行してみると特にパフォーマンスに変化はありませんでした。しかし、掲示板でコアが多いほうが遅いんだけどなんで?って質問があって、その答えにこんなものが。

In addition to Andy's good questions, have you tried enabling the server GC? If not, you should try that as well, by creating a .config file for your application containing:

<configuration>

<runtime>

<gcServer enabled="true"/>

</runtime>

</configuration>

Parallel.For Slows Down with more cores

サーバーGCを試してみてとのこと。

さっそく試してみると、パフォーマンスがぐぐっとアップしました。前回はタスクを大量につくらないように変更してパフォーマンスを上げましたが、そのような小細工をしていないコードがそれにせまるほどの約2倍も高速化しました。一番速いのはやはりタスクをほとんど作らないパターンで、これもごくごくわずかですが速くなりました。

プロセッサが 2 つ以上のコンピュータでは、サーバーのガベージ コレクションが最速のオプションとなります。

<gcServer> 要素

え?そうだったの!?ちょっといろいろ試してみる…。

結論 : コアが多い場合はサーバー GC を試してみるといいことあるかも。

2005 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 11 | 12 |
2006 | 01 | 02 | 03 | 04 | 06 | 09 | 11 | 12 |
2007 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 08 | 09 | 10 | 12 |
2009 | 01 | 03 | 04 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 07 |
2011 | 04 | 07 | 10 |
2012 | 04 | 12 |
2013 | 08 |
2014 | 03 | 08 |
2017 | 09 |