1

サーバーから画像をダウンロードし、画像がまだローカルに保存されていない場合はローカルに保存するアプリがあります。この例のために、同じ名前の画像がいくつかあるとしましょう。一度だけダウンロードして一度だけ保存したい。現時点では、私のアプリは要求されるたびにそれらをダウンロードしています - imageX.png のサーバーに対して行われた引数 10 の要求のために。リクエストが戻ってくると、アプリはそれらをアプリケーション データ フォルダーに imageX.png として保存しようとします。複数のスレッドが同時に同じファイルに書き込もうとしているため、これが私の問題の始まりです。

ここに私が現在持っているコードがあります

    public static async Task<BitmapImage> GetBitmapImage( string folderName, string fileName )
    {
        if( await FileExists( "\\Assets\\" + folderName, fileName ) )
        {
            return new BitmapImage( new Uri( Package.Current.InstalledLocation.Path + "/Assets/" + folderName + "/" + fileName, UriKind.RelativeOrAbsolute ) );
        }
        else
        {
            // Download and save locally
            HttpClient httpClient = new HttpClient();
            HttpRequestMessage request = new HttpRequestMessage( HttpMethod.Get, "http://www.mywebsite.com/request.php?action=getImage&name=" + WebUtility.UrlEncode( fileName ) );
            HttpResponseMessage response = await httpClient.SendAsync( request, HttpCompletionOption.ResponseHeadersRead );
            BitmapImage image = new BitmapImage();
            if( response.IsSuccessStatusCode )
            {
                InMemoryRandomAccessStream randomAccessStream = new InMemoryRandomAccessStream();
                DataWriter writer = new DataWriter( randomAccessStream.GetOutputStreamAt( 0 ) );
                writer.WriteBytes( await response.Content.ReadAsByteArrayAsync() );
                await writer.StoreAsync();

                await image.SetSourceAsync( randomAccessStream );

                var folderObj = await StorageFolder.GetFolderFromPathAsync( Package.Current.InstalledLocation.Path + "\\Assets\\" + folderName );
                var imageFile = await folderObj.CreateFileAsync( fileName, CreationCollisionOption.ReplaceExisting );
                var fs = await imageFile.OpenAsync( FileAccessMode.ReadWrite );
                writer = new DataWriter( fs.GetOutputStreamAt( 0 ) );
                writer.WriteBytes( await response.Content.ReadAsByteArrayAsync() );
                await writer.StoreAsync();
                writer.DetachStream();
                await fs.FlushAsync();
            }
            return image;
        }
    }

私が必要だと思うのは、前のスレッドがタスクを完了し、必要に応じてディスクに保存されるまで、「if FileExists」の前にスレッドを停止することです。スレッドの残りの部分は、FileExists 呼び出しで即座に true を返します。

4

2 に答える 2

3

私が必要だと思うのは、前のスレッドがタスクを完了し、必要に応じてディスクに保存されるまで、「if FileExists」の前にスレッドを停止することです。

それがあなたのやりたいことなら、 a を互換性のあるロックSemaphoreSlimの一種として使用できます。async

await semaphore.WaitAsync();
try
{
  if (await FileExists(...))
  ...
}
finally
{
  semaphore.Release();
}

ただし、これにより、すべてのダウンロードが一度に 1 回に制限されます。

于 2013-09-11T12:56:36.947 に答える
0

10 個のタスクが実行されており (それぞれが異なるイメージをダウンロード)、それぞれのタスクが完了するとすぐに何かを順次処理したいとします。

Task[] tasks = //...

while(tasks.Length != 0) {

    int index = Task.WaitAny(taks);
    var completedTask = tasks[index];
    var image = completedTask.Result;

    //save to file

    var tasksList = tasks.ToList();
    tasksList.RemoveAt(index);
    tasks = tasksList.ToArray();

}
于 2013-09-11T12:55:27.190 に答える