メソッドのブロックバージョンでTPLTaskFactory.FromAsync
を使用することとTaskFactory.StartNew
を使用することの間にパフォーマンスへの影響があるかどうか疑問に思いました。 100個以下の同時接続をサポートするTCPサーバーを作成しています。最初のオプションでコードを作成し、続行して複数の読み取りと書き込み操作を連鎖させた後、醜いままになりました。コードをデバッグするのは難しい。
同期バージョンでコードを記述し、それをタスクでラップすると、複雑さが軽減され、テスト容易性が向上すると思いますが、これを行うことによるパフォーマンスへの影響が心配です。
たとえば、次の2つの呼び出しの間にパフォーマンスの違いはありますか。
NetworkStream stream;
byte[] data;
int bytesRead;
//using FromAsync
Task<int> readChunk = Task<int>.Factory.FromAsync (
stream.BeginRead, stream.EndRead,
data, bytesRead, data.Length - bytesRead, null);
//using StartNew with blocking version
Task<int> readChunk2 = Task<int>.Factory.StartNew(() =>
stream.Read(data, bytesRead, data.Length - bytesRead));
APIがメソッドのBeginXXX/EndXXXバージョンを提供する場合、絶対にFromAsync
を使用したいと考えています。違いは、Stream
またはSocket
またはWebRequest
のようなものの場合、実際にはカバーの下で非同期I/Oを使用することになるということです(例:I/O Windowsの完了ポート)。これは、同期操作を実行する複数のCPUスレッドをブロックするよりもはるかに効率的です。これらの方法は、I/Oスケーラビリティを実現するための最良の方法を提供します。
非同期ニルヴァーナを実現するためにこれら2つのプログラミングモデルを組み合わせる方法の詳細については、MSDNの.NET SDKのこのセクション TPLおよび従来の.NET非同期プログラミング を確認してください。
外部リンクからのコピーをたどる:
はい。 .NET 4では、タスク並列ライブラリにAPMパターン(開始/終了)の組み込みラッパーであるTask.Factory.FromAsyncが含まれています。たとえば、StreamのBeginRead/EndReadメソッドを呼び出すためのタスクを作成する場合は、次のようにすることができます。
Stream s = ...;
byte [] buffer = ...;
Task<int> numBytesRead = Task<int>.Factory.FromAsync(s.BeginRead, s.EndRead, buffer, 0, buffer.Length, null);
// or with await
int numBytesRead = await Task<int>.Factory.FromAsync(s.BeginRead, s.EndRead, buffer, 0, buffer.Length, null);
裏では、FromAsyncはTaskCompletionSourceの上に構築されています。この読み取り例のFromAsyncの単純なバージョンは、次のようになります。
var tcs = new TaskCompletionSource<TResult>();
s.BeginRead(buffer, 0, buffer.Length, iar =>
{
try { tcs.SetResult(s.EndRead(iar)); }
catch(Exception exc) { tcs.SetException(exc); }
}, null);
Task<int> numBytesRead = tcs.Task;
http://social.msdn.Microsoft.com/Forums/en/async/thread/ed8a14e8-d19a-42d1-bc3f-7017bdfed09c