2017-12-13 25 views
0

以下のようなタイムアウトのシンプルな非同期書き込みをコーディングし、非常に大きなバッファと小さなwaitTimeを指定すると、関数がTaskCanceledExceptionをスローすると考えます。しかし、これは起こりません。 WriteAsyncは、書き込みが完了するまで数秒間ブロックします。私は何が欠けていますか? GUIスレッドからタイムアウトのあるWriteAsync

public async void WriteWithTimeout(Stream os, byte[] buf, int waitMs) 
{ 
    CancellationTokenSource tokenSource = new CancellationTokenSource(waitMs); // cancel after waitMs milliseconds. 
    await os.WriteAsync(buf, 0, buf.Length, tokenSource.Token); 

    return; 
} 

コール:

try 
{ 
    WriteWithTimeout(response.OutputStream, buf100M, w1ms); 
} 
catch(OperationCanceledException e) 
{ 
    ConsoleWriteLine("Failed with exception: {0}", e.Message); 
}   
+0

あなたは 'tokenSource.CancelAfter(のTimeSpanを行うべきではありませんコンストラクタにFileOptions.Asynchronousに合格しない場合FileStreamのデフォルトの動作です。たとえば。 FromMilliseconds(waitMs)); 'AFTER' WriteAsync'そしてそれを待っていますか?例えばこの回答はここにあります:https://stackoverflow.com/questions/23476576/cancellationtoken-timeout-vs-task-delay-and-timeout – zaitsman

+0

私は夢中ですか、これは私がする必要があるのですか: Task task = response.OutputStream .WriteAsync(buf、0、buf.Length); if(task.Wait(maxWait)) { // OK。 } else { //タイムアウトしました。 } –

答えて

9

あなたは非同期ボイドをキャッチすることはできません。それはタスクを返さなければならず、あなたはそれを待たなければなりません。

public async Task WriteWithTimeout(Stream os, byte[] buf, int waitMs) 
{ 
    CancellationTokenSource tokenSource = new CancellationTokenSource(waitMs); // cancel after waitMs milliseconds. 
    await os.WriteAsync(buf, 0, buf.Length, tokenSource.Token); 

    return; 
} 

GUIコード

try 
{ 
    await WriteWithTimeout(response.OutputStream, buf100M, w1ms); 
} 
catch(OperationCanceledException e) 
{ 
    ConsoleWriteLine("Failed with exception: {0}", e.Message); 
} 

キャンセルはまだ起きていますが、単にそれを守りません。

更新:

os.WriteAsync(がちょうど舞台裏Task.Run(に裏打ちされただけで、同期完了であることが可能です。キャンセルトークンは既に実行中のTask.Run(をキャンセルしません。その場合、最善の方法は、Task.WhenAny(にキャンセルをラップし、無限に長いTask.Delay(経由でそこにトークンを渡すことです。

public async Task WriteWithTimeout(Stream os, byte[] buf, int waitMs) 
{ 
    CancellationTokenSource tokenSource = new CancellationTokenSource(waitMs); // cancel after waitMs milliseconds. 
    var task = os.WriteAsync(buf, 0, buf.Length, tokenSource.Token); 
    var waitedTask = await Task.WhenAny(task, Task.Delay(-1, token)); 
    await waitedTask; //Wait on the returned task to observe any exceptions. 
} 

1.あなたは

+0

非同期タスクで待機中です。ありがとうございました。私はいくつかのカジュアルなユーザーにライブラリを提供する必要があり、async-awaitでそれらを気にしたくありません。だから、次のように別の関数でWriteWithTimeoutをラップしようとします。 try { タスクタスク= WriteWithTimeout(response.OutputStream、buf100M、w1ms); } –

+0

(上記から続行します。申し訳ありませんが、メッセージのフォーマットに問題があります) task.Wait(); } catch(例外e) { } また、キャンセルは無視され、WriteAsyncは書き込み操作が完了するまでブロックされます。 –

+0

UIスレッドで 'task.Wait()'を呼び出してUIを応答させることはできません。それだけで動作します。あなたのUIがロックされないようにするには、awaitを使用するか、 'this.BeginInvoke(' to仕事が 'Task.Run(' –

関連する問題