2

ファイルをダウンロードするメソッドを呼び出すコードがいくつかあります。

private async Task DownloadFile()
{
    WebClient client = new WebClient();

    var downloadTask =
        Task.Run(
            () =>
                client.DownloadFile("http://www.worldofcats.com/bigkitty.zip",
                    "c:\\cats\\"
         );

    await downloadTask;
}

このメソッドを呼び出すには、次のようにします。

var downloadTask = DownloadFile();

await downloadTask;

これはフォーム アプリの一部であるため、UI が応答しない状態でダウンロードしている間は問題ありません。唯一の問題は、DownloadFile メソッドにはタイムアウトがなく、時々エラーが発生したりハングしたりする可能性があるため、タイムアウトを設定する必要があることです。

使用するTask.Wait(x);と、UI スレッドがブロックされます。おそらく使用できると思いますawait Task.WhenAny(downloadTask, () => Thread.Sleep(50000));が、これが最善の方法かどうかはわかりません。

だから私の質問は、これを解決するにはどうすればいいですか?また、タスクが強制終了された場合、タスクをクリーンアップするにはどうすればよいですか? (それとも、気にしなくていいの?)

4

2 に答える 2

3

キャンセルを認識しないタスクには適していない古いソリューション

渡す必要がありCancellationTokenます:

private async Task DownloadFile()
{
    WebClient client = new WebClient();
    using(var cts = new CancellationTokenSource(TimeSpan.FromSeconds(60))
    {        
        var downloadTask =
            Task.Run(
                () =>
                    client.DownloadFile("http://www.worldofcats.com/bigkitty.zip",
                        "c:\\cats\\"),
                 cts.Token
             );
        await downloadTask;
    }
}

(または)をキャッチするためにブロックawait DownloadFile()でラップできる場合:try/catchTaskCanceledExceptionOperationCanceledException

try
{
    await DownloadFile();   
}
catch(TaskCanceledException)
{
    //Timeout!
}

[編集]

コメントで気づいたように、キャンセルを認識していないタスクをキャンセルすることはできません - どういうわけか私はそれを忘れていました (ブー!)。しかし、心配する必要はありません。 DownloadFileTaskAsyncandを使用して修正できるCancelAsyncため、キャンセル トークンも必要ありません。

var downloadTask = client.DownloadFileTaskAsync("http://www.worldofcats.com/bigkitty.zip",
                        "c:\\cats\\");
var timerTask = Task.Delay(TimeSpan.FromSeconds(60));

await Task.WhenAny(downloadTask, timerTask);
client.CancelAsync(); // This does nothing if there's no operation in progress, as noted in documentation
于 2013-09-09T11:06:04.430 に答える