この問題は、Windows 7、.NET 4.5(または実際には4.0ランタイム)とF#/ Deedleでのテール再帰の多用を組み合わせたものであることが判明しました。
Visual Studioの並行処理ビジュアライザを使用して、Invoke呼び出しで待機する時間が最もかかっていることがわかりました。精密検査では、次のコールトレースでこれらの結果:
ntdll.dll:RtlEnterCriticalSection
ntdll.dll:RtlpLookupDynamicFunctionEntry
ntdll.dll:RtlLookupFunctionEntry
clr.dll:JIT_TailCall
<some Deedle/F# thing>.Invoke
これらの機能を検索するには、F#を使用すると、JIT_TailCallへの呼び出しの多くにつながることを示す複数の記事やフォーラムのスレッドを与え、その.NET 4.6は、新しいを持っていますJITコンパイラは、これらの呼び出しに関連するいくつかの問題に対処しているようです。ロック/同期に関連する問題に言及しているものは見つかりませんでしたが、.NET 4.6へのアップデートが解決策であるという考えが私に与えられました。
ただし、.NET 4.5も使用している自分のWindows 8.1システムでは、この問題は発生しません。同様の呼び出しコールのビットを検索した後、私は次のように、このシステム上のコールトレースが見えたことがわかった:
ntdll.dll:RtlAcquireSRWLockShared
ntdll.dll:RtlpLookupDynamicFunctionEntry
ntdll.dll:RtlLookupFunctionEntry
clr.dll:JIT_TailCall
<some Deedle/F# thing>.Invoke
はどうやら、Windowsの8(0.1)にロック機構がもたらした、あまり厳密なものに変更されましたロックを待つ必要があまりありません。
Windows 7の厳密なロックと.NET 4.5の非効率なJITコンパイラの両方のターゲットシステムの組み合わせでのみ、F#の大量のテール再帰が問題を引き起こしました。 .NET 4.6にアップデートした後、問題は消え、私たちのサービスは期待どおりに動作しています。
私はDeedleがプログラムの実行を遅らせる洗練されたスレッド同期を行っていないと思っていますが、複数のスレッドから同じフレーム/シリーズにアクセスしている場合、CPUキャッシュに影響する可能性があります並列化のオーバーヘッドは、並列化の利点よりも大きくなります。 –
@TomasPetricek私たちの使い方については、スレッドはかなり独立していると見なすことができます。もちろん、図書館で何が起こるか(あるいはCLRではさらに深いこと)は言うことができません。私が測定できた限り(例えば、インテルのPCMで)、キャッシングは問題ではありません。奇妙なことは、(両方のシステムで)スレッドの数を制限するときに、少なくとも現在のシステムと同様に実行することを期待することです。 – mweerden
スレッドに余計なことがなくなればすぐにスレッドをアイドル状態にするのに十分なスリープステートメントがコード内にありますか?スレッドが競合しているようですが、休憩をとることなくループしているだけでしょうか? –