加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

完成c#任务再次运行……为什么?

发布时间:2020-12-15 23:28:56 所属栏目:百科 来源:网络整理
导读:我对我的代码[下面]的行为感到有点困惑.我正在开发一个专门的命令行实用程序,可以下载和处理一些文件.我想尽可能使用c#的异步功能.创建任务并使用Task.WaitAll()时,代码段按预期运行.在等待之后,我有2个任务,这两个任务都被标记为已完成.问题:我尝试从任务
我对我的代码[下面]的行为感到有点困惑.我正在开发一个专门的命令行实用程序,可以下载和处理一些文件.我想尽可能使用c#的异步功能.创建任务并使用Task.WaitAll()时,代码段按预期运行.在等待之后,我有2个任务,这两个任务都被标记为已完成.问题:我尝试从任务中获取结果最终会再次运行这两个任务!为什么是这样?如何在不执行第二次任务的情况下读取结果?

private IEnumerable<Task<FileInfo>> DownloadFiles()
    {
        int fileCount = 1;

        Console.Clear();
        Console.SetCursorPosition(0,0);
        Console.Write("Download files...");

        yield return DownloadFile(Options.SkuLookupUrl,"SkuLookup.txt.gz",fileCount++,f =>
        {
            return DecompressFile(f);
        });
        yield return DownloadFile(Options.ProductLookupUrl,"ProductList.txt.gz",f =>
        {
            return DecompressFile(f);
        });
    }

    public void Execute()
    {
        var tasks = DownloadFiles();
        Task.WaitAll(tasks.ToArray());

        Console.WriteLine();
        Console.WriteLine("Download(s) completed.  Parsing sku lookup file.");
        FileInfo[] files = tasks.Select(t => t.Result).ToArray(); // <-- triggers a second round of task execution

        ParseSkuLookups(files.SingleOrDefault(f => f.Name.ToLowerInvariant().Contains("skulookup")));
    }

如果相关的是下载方法:

private async Task<FileInfo> DownloadFile(string targetUrl,string destinationFile,int lineNumber,Func<FileInfo,FileInfo> callback = null)
    {
        FileInfo fi = new FileInfo(destinationFile);

        if (!Options.NoCleanup || !fi.Exists)
        {
            WebClient client = new WebClient();
            client.DownloadProgressChanged += (s,e) =>
            {
                char spinnerChar;

                switch ((e.ProgressPercentage % 10))
                {
                    case 0: spinnerChar = '|'; break;
                    case 1: spinnerChar = '/'; break;
                    case 2: spinnerChar = '-'; break;
                    case 3: spinnerChar = '|'; break;
                    case 4: spinnerChar = ''; break;
                    case 5: spinnerChar = '|'; break;
                    case 6: spinnerChar = '/'; break;
                    case 7: spinnerChar = '-'; break;
                    case 8: spinnerChar = ''; break;
                    default:
                    case 9: spinnerChar = '|'; break;

                }
                lock (ConsoleLockSync)
                {
                    Console.SetCursorPosition(0,lineNumber);
                    Console.WriteLine(String.Format("{0} download: {1}% {2}",destinationFile,e.ProgressPercentage==100 ? "[Complete]" : spinnerChar.ToString()));
                }
            };
            await client.DownloadFileTaskAsync(new Uri(targetUrl,UriKind.Absolute),destinationFile);
        }
        else if(Options.NoCleanup)
        {
            lock (ConsoleLockSync)
            {
                Console.SetCursorPosition(0,lineNumber);
                Console.WriteLine(String.Format("{0} download: Skipped [No Cleanup]        ",destinationFile));
            }
        }
        fi.Refresh();
        return callback != null ? callback(fi) : fi;
    }

解决方法

如果每次枚举结果时都有一个带有yield返回值的IEnumerable,它将重新运行你的函数. task.WaitAll中的tasks.ToArray()(tasks.ToArray());枚举它然后再在任务中枚举它.选择(t => t.Result).ToArray();.要使其枚举,请保留第一个ToArray()调用的结果,然后在整个方法中重复使用该结果.

public void Execute()
{
    var tasks = DownloadFiles();
    var taskArray = tasks.ToArray();
    Task.WaitAll(taskArray);

    Console.WriteLine();
    Console.WriteLine("Download(s) completed.  Parsing sku lookup file.");
    FileInfo[] files = taskArray.Select(t => t.Result).ToArray(); // <-- notice we use taskArray here instead of tasks.

    ParseSkuLookups(files.SingleOrDefault(f => f.Name.ToLowerInvariant().Contains("skulookup")));
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读