【问题标题】:Asynchronous FileIO methods mixing up images in WinRT application在 WinRT 应用程序中混合图像的异步 FileIO 方法
【发布时间】:2014-09-14 20:37:55
【问题描述】:

因此,我在我的应用程序中实现了一种方法,该方法从站点下载给定漫画的图像,并将所述图像放入应用程序的 AppData (localstate) 文件夹中,位于 language 文件夹中的 title 文件夹中。

图像下载工作完美,除了如果我尝试一次下载多个图像集,结果会在所涉及的文件夹中混合。

处理File IO的方法:

private async Task<bool> SaveManga(Data.Posts.Content2 manga)
    {
        var folder = ApplicationData.Current.LocalFolder;
        var safeName = Path.GetInvalidFileNameChars().Aggregate(manga.ContentInfo.ContentName, (current, c) => current.Replace(c, '_').Replace('.', '_'));

        // Create folder for issue if does not exist
        var issueFolder = await ApplicationData.Current.LocalFolder.CreateFolderAsync(safeName, CreationCollisionOption.OpenIfExists);
        // Create folder for language if does not exist
        var langFolder = await issueFolder.CreateFolderAsync(manga.ContentInfo.ContentLanguage, CreationCollisionOption.OpenIfExists);

        // Populate pages if page count is 0
        if (manga.Pages == null)
            manga.Pages = new Dictionary<int, Data.Posts.Page>();
        if (manga.Pages.Count == 0)
        {
            if (NetworkInterface.GetIsNetworkAvailable() == false)
            {

            }
            var pages = Fakku.GetMangaInfo(manga.ContentInfo.ContentUrl).Result.Pages;
            for (var i = 0; i < pages.Count; i++)
            {
                var page = new Data.Posts.Page { Image = pages.Values.ElementAt(i).Image, Thumb = pages.Values.ElementAt(i).Thumb };
                manga.Pages.Add(i, page);
            }
        }
        var files = await langFolder.GetItemsAsync();
        var fileCount = files.Count;
        if (fileCount + 3 == manga.ContentInfo.ContentPages) return true;
        var cbi = new BitmapImage(new Uri(manga.ContentInfo.ContentImages.Cover));
        const string cname = "cover.jpg";
        var wcbi = await WriteableBitmapFromBitmapImageExtension.FromBitmapImage(cbi);
        await wcbi.SaveToFile(langFolder, cname, CreationCollisionOption.OpenIfExists);


        var sbi = new BitmapImage(new Uri(manga.ContentInfo.ContentImages.Sample));
        const string sname = "sample.jpg";
        var wsbi = await WriteableBitmapFromBitmapImageExtension.FromBitmapImage(sbi);
        await wsbi.SaveToFile(langFolder, sname, CreationCollisionOption.OpenIfExists);

        for (var i = 1; i < manga.ContentInfo.ContentPages; i++)
        {
            var bi = new BitmapImage(new Uri(manga.Pages[i].Image));
            //var x = await langFolder.CreateFileAsync(String.Format("{0}.png", i), CreationCollisionOption.ReplaceExisting);
            var imgName = String.Format("{0}.jpg", i);
            try
            {
                var wbi = await WriteableBitmapFromBitmapImageExtension.FromBitmapImage(bi);
                await wbi.SaveToFile(langFolder, imgName, CreationCollisionOption.OpenIfExists);
            }
            catch (Exception e)
            {
                var hResult = (uint)e.HResult;
                if (hResult.Equals(0x80190194))
                {
                    new MessageDialog("Error loading pages. \n  If this is a sample manga, this behavior is to be expected.").ShowAsync();
                    break;
                }
            }
        }
        return true;
    }

以及实现:

private async void SaveButton_Click(object sender, RoutedEventArgs e)
    {
        SaveButton.IsEnabled = false;
        if (isSaved)
        {
            var i = defaultViewModel.ContentInfo;
            Fakku.SavedManga.RemoveAll(x => x.ContentInfo.ContentUrl == i.ContentUrl);
            isSaved = !isSaved;
            SaveButton.Content = "Save";
            var manga = defaultViewModel;
            await RemoveManga(manga);
            await ProcessSaved();
            SaveButton.IsEnabled = true;
        }
        else if (!isSaved)
        {
            Fakku.SavedManga.Add(defaultViewModel);
            isSaved = true;
            SaveButton.Content = "Remove";
            try
            {
                var manga = defaultViewModel;
                //pendingWork = SaveManga(manga);

                _saves.Enqueue(manga);
                await AsyncParallelForEach(
_saves, async save => await SaveManga(manga), 8,
TaskScheduler.FromCurrentSynchronizationContext());
                //HandleSaving();
                await ProcessSaved();
            }
            catch (NullReferenceException)
            {

            }
            SaveButton.IsEnabled = true;
        }
    }

AsParallel 函数:

private static Task AsyncParallelForEach<T>(
IEnumerable<T> source, Func<T, Task> body,
int maxDegreeOfParallelism = DataflowBlockOptions.Unbounded,
TaskScheduler scheduler = null)
    {
        var options = new ExecutionDataflowBlockOptions
        {
            MaxDegreeOfParallelism = maxDegreeOfParallelism
        };
        if (scheduler != null)
            options.TaskScheduler = scheduler;

        var block = new ActionBlock<T>(body, options);

        foreach (var item in source)
            block.Post(item);

        block.Complete();
        return block.Completion;
    }

parallel foreach 的使用是我最近的尝试,取自 this 文章,但结果与我上面描述的相似,我觉得我仍然遗漏了一些非常重要的东西。

谁能指出我正确的方向?我正在尝试找到一种方法来处理这些下载,即同时处理 SaveManga 方法的多个实例,或者至少将它们排队等待完成。

编辑:我开始意识到我需要关注的是并行化,而不是异步性,如果我想同时运行下载,这是我更喜欢的。

【问题讨论】:

  • 你到底在问什么?从你的文章中真的不清楚。
  • 很抱歉。我正在尝试在自己指定的文件夹中并行下载不同的项目,每个项目都有自己的一组图像。

标签: c# asynchronous windows-runtime winrt-async


【解决方案1】:

我认为问题在于您也在并行化初始化(文件夹创建 + 页数),然后它混淆了一切。

我建议先进行初始化:

public async Task InitAsync(Data.Posts.Content2 manga){
    var folder = ApplicationData.Current.LocalFolder;
        var safeName = Path.GetInvalidFileNameChars().Aggregate(manga.ContentInfo.ContentName, (current, c) => current.Replace(c, '_').Replace('.', '_'));

        // Create folder for issue if does not exist
        var issueFolder = await ApplicationData.Current.LocalFolder.CreateFolderAsync(safeName, CreationCollisionOption.OpenIfExists);
        // Create folder for language if does not exist
        var langFolder = await issueFolder.CreateFolderAsync(manga.ContentInfo.ContentLanguage, CreationCollisionOption.OpenIfExists);

        // Populate pages if page count is 0
        if (manga.Pages == null)
            manga.Pages = new Dictionary<int, Data.Posts.Page>();
        if (manga.Pages.Count == 0)
        {

            var pages = Fakku.GetMangaInfo(manga.ContentInfo.ContentUrl).Result.Pages;
            for (var i = 0; i < pages.Count; i++)
            {
                var page = new Data.Posts.Page { Image = pages.Values.ElementAt(i).Image, Thumb = pages.Values.ElementAt(i).Thumb };
                manga.Pages.Add(i, page);
            }
        }

        var cbi = new BitmapImage(new Uri(manga.ContentInfo.ContentImages.Cover));
        const string cname = "cover.jpg";
        var wcbi = await WriteableBitmapFromBitmapImageExtension.FromBitmapImage(cbi);
        await wcbi.SaveToFile(langFolder, cname, CreationCollisionOption.OpenIfExists);


        var sbi = new BitmapImage(new Uri(manga.ContentInfo.ContentImages.Sample));
        const string sname = "sample.jpg";
        var wsbi = await WriteableBitmapFromBitmapImageExtension.FromBitmapImage(sbi);
        await wsbi.SaveToFile(langFolder, sname, CreationCollisionOption.OpenIfExists);
}

然后只做一些像这样的并行化,因为框架将足够聪明来管理线程:) :

  List<Task> tasksToWait = new List<Task>();
for (var i = 1; i < manga.ContentInfo.ContentPages; i++)
        {
taskToWait.Add(Task.Run(()=>SaveMangaPage(i));
}
await Task.WhenAll(tasksToWait );
await ProcessSaved();

SaveMangaPage 是:

public async Task SaveMangaPage(int pageNumber) {

 var bi = new BitmapImage(new Uri(manga.Pages[pageNumber].Image));
 //var x = await langFolder.CreateFileAsync(String.Format("{0}.png", pageNumber), CreationCollisionOption.ReplaceExisting);
 var imgName = String.Format("{0}.jpg", pageNumber);
 try
   {
  var wbi = await WriteableBitmapFromBitmapImageExtension.FromBitmapImage(bi);
  await wbi.SaveToFile(langFolder, imgName, CreationCollisionOption.OpenIfExists);
 }
 catch (Exception e)
  {
     var hResult = (uint)e.HResult;
     if (hResult.Equals(0x80190194))
     {
                    new MessageDialog("Error loading pages. \n  If this is a sample manga, this behavior is to be expected.").ShowAsync();
                    break;
      }
 }
}
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多