web-dev-qa-db-ja.com

非同期File.Delete / Create / Moveを実装する方法は?

アプリケーションで多くのファイルI/O操作を実行する必要があるため、それらを非同期で実装することにしました。 MSDNを調べると、File.Create、File.Delete、およびFile.Moveに対応する非同期のものはありません。私が学んだように、その理由は、ファイルの削除、作成、または移動のための非同期Win32実装が存在しないため、次の解決策になりました。

public static Task DeleteAsync(string path)
{
     Guard.FileExists(path);

     return Task.Run(() => File.Delete(path));
}

public static Task<FileStream> CreateAsync(string path)
{
     Guard.IsNotNullOrWhitespace(path);

     return Task.Run(() => File.Create(path));
}

public static Task MoveAsync(string sourceFileName, string destFileName)
{
     Guard.FileExists(sourceFileName);
     Guard.IsNotNullOrWhitespace(destFileName);

     return Task.Run(() => { File.Move(sourceFileName, destFileName); });
}

パラダイムを考えると "Task.Run in Librariesを使用しないでください" 、より良い実装があるのか​​、それとも同期コードにフォールバックする必要があるのか​​疑問に思います。

よろしくお願いします!

編集:


  • PeterDunihoの推奨に基づいてコードを改善しました
  • SriramSakthivelによって提供された元のブログ投稿へのリンクを追加しました
13
Fabe

これを行う必要がある場合は、次のような方法を記述します(注:これが、Stephens ClearyとToubが私たちにそうしないように促していることとまったく同じであることにすぐに同意します):

_public static Task DeleteAsync(string path)
{
     Guard.FileExists(path);

     return Task.Run(() => { File.Delete(path); });
}

public static Task<FileStream> CreateAsync(string path)
{
     Guard.IsNotNullOrWhitespace(path);

     return Task.Run(() => File.Create(path));
}

public static Task MoveAsync(string sourceFileName, string destFileName)
{
     Guard.FileExists(sourceFileName);
     Guard.IsNotNullOrWhitespace(destFileName);

     return Task.Run(() => { File.Move(sourceFileName, destFileName); });
}
_

これにより、コードが少しクリーンアップされ、過度のコンテキスト/スレッド切り替えが排除されます。

GUIベースのプログラムのコンテキストでは、このようなラッパーを使用するのは問題ないようです。参照されている記事で説明されているように、同期APIと非同期APIを並行して使用してまったく新しいライブラリを作成しない限り、これはひどいことではないと思います。

しかし、私にとってより大きな問題は、これらの操作のいずれも、そもそも非同期にすることを正当化するのに十分な時間がかかる可能性がないということです。つまりUIスレッドからTaskで処理を実行する通常の理由は、操作が完了するまでUIスレッドが待機する余裕がないためです。ただし、ここでは、これらの操作のそれぞれについて、操作をスレッドプールに送信し、実行後に継続を取得するという行為は、操作自体と同じくらい多くのパフォーマンスオーバーヘッドをプログラムに追加する可能性があります。

thatの理由で、非同期バージョンのメソッドをまったく気にしないことをお勧めします。 UIから直接Create()Delete()、およびMove()メソッドを呼び出すだけです。

(注:上記の1つの例外は、Move()が実際にデータをコピーすることを伴う、ネットワーク共有または異なるボリュームを処理する場合です。したがって、それでも、それは非常に大きな「依存」です。同様に、Delete()Create()は通常、ネットワーク上でも高速ですが、操作が実際に失敗する場合は時間がかかる可能性があります。実際には、そこで操作を非同期で実行するための良い使用例があるかもしれません。 )。

9
Peter Duniho