【问题标题】:How to find out which Task has finished如何找出哪个任务已完成
【发布时间】:2019-04-29 08:55:48
【问题描述】:

我有一个异步代码可以将目录中的所有文件上传到 API。它工作正常,但我想跟踪哪个文件已上传并想要记录,以便我可以进行一些状态检查。

我一直在关注 this guidethis one 。第一个为每个文件和第二个链接创建明确的任务,只讨论显示剩余的任务数量。另一方面,我想找出哪个任务已完成,将其打印到日志中并继续等待,直到没有要上传的文件为止。我正在使用 SSIS 中的脚本组件来执行此操作。

这是专门为 2 个文件定义 2 个任务的时候。

            Task<string> uploadCounterpartFileTask = UploadFiles(year, month, filename_counterparts, accesstoken, path);
            Task<string> uploadProductCategoryFileTask = UploadFiles(year, month, filename_productcategories, accesstoken, path);

            var allTasks = new List<System.Threading.Tasks.Task> { uploadCounterpartFileTask, uploadProductCategoryFileTask };


            while (allTasks.Any())
            {
                System.Threading.Tasks.Task finished = await System.Threading.Tasks.Task.WhenAny(allTasks);
                if (finished == uploadCounterpartFileTask)
                {
                    allTasks.Remove(uploadCounterpartFileTask);
                    var counterpartFile = await uploadCounterpartFileTask;
                }
                else if (finished == uploadProductCategoryFileTask)
                {
                    allTasks.Remove(uploadProductCategoryFileTask);
                    var productCategoriesFile = await uploadProductCategoryFileTask;
                }
            }

但我现在不想这样做,因为我不知道目录中有多少文件

我想上传一个目录中的所有文件,像这样。:-

string[] fileSystemEntries = Directory.GetFileSystemEntries(path);

            var tasks = fileSystemEntries.OrderBy(s => s).Select(
            fileName => UploadFiles(year, month, Path.GetFileName(fileName), accesstoken, path));
            while (tasks.Any())
            {

                var finished = await System.Threading.Tasks.Task.WhenAny(tasks);



                    Dts.Events.FireInformation(0, "Script Task for uploading AVRO files", "File Uploaded" + finished.Result, string.Empty, 0, ref fireAgain);
                    tasks.Remove(finished);


            }
            Dts.Events.FireInformation(0, "Script Task for uploading AVRO files", "All Files Uploaded", string.Empty, 0, ref fireAgain);

我正在使用finished.Result,因为MSDN 上的文档指出Result 给出了在whenAny 之后完成的任务。我知道 whenAny 给出第一个,因此我正在循环(类似于 MSDN 上的示例)。

您会看到 Dts.Events.FireInformation,因为它位于 SSIS 的脚本任务中。

我希望它会在日志中说类似的内容。

上传的文件:Counterparts.avro

上传的文件:ProductCategorties.avro

上传的文件:SomeOtherFile.avro

所有文件已上传。

但是,虽然文件上传正常,但没有打印任何语句。

如何让它们打印出来?我只是不想对所有文件都有一个通知,我真的很想知道上传了哪个文件的状态。

编辑:针对其中一个 cmets,这里是 UploadFiles 的代码。基本上,它将文件上传到 API,并且每个文件涉及 3 个 REST 调用。

    private async Task<string> UploadFiles(string year, string month, string filename, string accesstoken, string path)
    {
        //Initial Put
        var method = new HttpMethod("PUT");
        string url = String.Format("https://someurl/part1/{0}/{1}/{2}?resource=file&recursive=True", year, month, filename);


        var request = new HttpRequestMessage(method, url)
        {
            Content = null
        };

        request.Headers.Add("Authorization", "Bearer " + accesstoken);


        var initput = await client.SendAsync(request);

        //Append Data
        url = String.Format("https://someurl/part1/{0}/{1}/{2}?action=append&position=0", year, month, filename);

        string SourceFile = path;
        var content = new MultipartFormDataContent();
        string filenamefullyqualified = path + filename;
        Stream fs = System.IO.File.Open(filenamefullyqualified, FileMode.Open, FileAccess.Read, FileShare.None);
        content.Add(CreateFileContent(fs, filename, "text/plain"));

        method = new HttpMethod("PATCH");

        request = new HttpRequestMessage(method, url)
        {
            Content = content
        };

        //long filelength = new System.IO.FileInfo(filenamefullyqualified).Length;

        request.Headers.Add("Authorization", "Bearer " + accesstoken);

        var response = await client.SendAsync(request);

        long? position = request.Content.Headers.ContentLength;

        //Flush Data

        url = String.Format("https://someurl/part1/{0}/{1}/{2}?action=flush&position={3}", year, month, filename, position.ToString());

        request = new HttpRequestMessage(method, url)
        {
            Content = null
        };

        request.Headers.Add("Authorization", "Bearer " + accesstoken);


        response = await client.SendAsync(request);


        return filename;

    }

编辑 2:回应评论。请注意,这是我正在尝试演示此问题的示例代码。

    public async void Main()
    {
        bool fireAgain = true;
        HttpClientHandler httpClientHandler = new HttpClientHandler()
        {
            Proxy = new WebProxy("http://127.0.0.1:8888")
            {
                UseDefaultCredentials = true,
                BypassProxyOnLocal = true
            },
            UseDefaultCredentials = true
        };

        string year = "2019";
        string month = "02";
        string path = "D:\\SomeFolder\\AVRO\\";

        client = new HttpClient(handler: httpClientHandler, disposeHandler: true);
        string resp = getBearerToken().GetAwaiter().GetResult();
        var ser = new JavaScriptSerializer();
        var result = ser.DeserializeObject(resp);
        Dictionary<string, object> BearerTokenDetails = new Dictionary<string, object>();
        BearerTokenDetails = (Dictionary<string, object>)(result);

        string accesstoken = BearerTokenDetails["access_token"].ToString();
        Dts.Events.FireInformation(0, "Script Task for uploading AVRO files", "Access Code: " + accesstoken, string.Empty, 0, ref fireAgain);


        string[] fileSystemEntries = Directory.GetFileSystemEntries(path);

        var tasks = fileSystemEntries.OrderBy(s => s).Select(
        fileName => UploadFiles(year, month, Path.GetFileName(fileName), accesstoken, path));

        await System.Threading.Tasks.Task.WhenAll(tasks);
        Dts.Events.FireInformation(0, "Script Task for uploading AVRO files", "All Files Uploaded", string.Empty, 0, ref fireAgain);


    }

您会看到我定义为异步的 getBearerToken 方法,但后来使用 GetResult 将其设为 Blocked 调用,因为这需要首先发生。另外,需要注意的是 - 您在 Bearer Token 之后看到的第一个 FireInfo ,仅在我将其设为阻塞调用后才起作用(GetResult 在我阅读时会这样做)。

【问题讨论】:

  • 请检查您提供的第二个链接中的代码,它有您的答案。有一个循环检查条件tasks.Count != 0,因为在循环内你不断删除任务,因为他们完成并处理它们,当计数变为 0 时循环停止,即所有任务都已处理。
  • 但是 dts.Events.FireInfo 在循环内,而 remove 在 Dts.events.FireInfo 之后。请注意,我有 2 个 Dts.Events.FireInfo。也许,您只查看了外部文件,即完成后的所有文件。还有一个,在循环内。
  • 方法UploadFiles的代码是什么?
  • 如果你只想记录日志,假设UploadFile返回一个Task&lt;T&gt;对象,你可以使用ContinueWith方法,代理将在UploadFile完成后立即被调用.
  • @PeterBons:更新了问题以包含它。

标签: c# asynchronous async-await task


【解决方案1】:

假设 FireInformation 按预期工作,您的代码可以大大简化。

您可以在UploadFiles 中记录每个任务的完成情况:

private async Task<string> UploadFiles(string year, string month, string filename, string accesstoken, string path)
{
    // stuff


    response = await client.SendAsync(request);

    // Log task finished
    Dts.Events.FireInformation(0, "Script Task for uploading AVRO files", "File Uploaded" + filename, string.Empty, 0, ref fireAgain);  

    return filename;
}

方法的结束是文件上传完成任务的时刻。不需要 while 循环和手动从数组中删除任务。

如果它只是用于日志记录,它认为你甚至不需要返回文件名了

要记录所有已完成的消息,只需在Task.WhenAll 之后写一个日志文件:

        string[] fileSystemEntries = Directory.GetFileSystemEntries(path);

        var tasks = fileSystemEntries.OrderBy(s => s).Select(
        fileName => UploadFiles(year, month, Path.GetFileName(fileName), accesstoken, path));

        await Task.WhenAll(tasks);
        Dts.Events.FireInformation(0, "Script Task for uploading AVRO files", "All Files Uploaded", string.Empty, 0, ref fireAgain);

现在,由于您在控制台中运行,您有两个选择,使用 public async Task Main() 作为方法签名(需要 c# 7.1,请参阅 this)或将 await Task.WhenAll(tasks); 更改为 Task.WaitAll(tasks); 否则应用程序将不会t 等待您的代码完成,因此不会显示任何输出。

另外一个选项是在 Main 方法的最后添加行 Console.ReadKey(); 并等待输出显示。

【讨论】:

  • 非常感谢。我也试过了,但它只是不打印。因此,我试图像教程一样在外面打印它。所以,在任何时候都没有调试:什么都没有。并在“等待所有”处进行调试:仅上传文件:ProductCategorties.avro 和上传的所有文件。难道是因为stackoverflow.com/questions/42331050/…
  • @SaugatMukherjee 我的答案中的第二个代码 sn-p 包含在我假设的方法中,您的应用程序如何调用它?
  • 这在被定义为异步的 Main() 方法中调用,因为有一个等待,即它在:public async void Main() 中。我应该用某种方法把它包装起来,然后把它拿出来,这样 Main 就不是异步的吗?抱歉,但我对这种异步编程很陌生。
  • 编辑了问题以包含该问题,还包括一些信息。
  • 谢谢。这适用于 uploadFiles 方法中的打印。谢谢 :)。但是 main 方法中的那个,不打印。即所有上传的文件都不会打印。
猜你喜欢
  • 1970-01-01
  • 2012-12-24
  • 2014-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-12
  • 1970-01-01
  • 2011-05-13
相关资源
最近更新 更多