如何找出哪个任务已经完成

时间:2019-04-29 08:55:48

标签: c# asynchronous async-await task

我有一个异步代码,用于将目录中的所有文件上传到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);

我使用的是finish.Result,因为MSDN上的文档指出Result给出了whenAny之后完成的任务。我知道什么时候任何人都给出第一个,因此我正在循环播放(类似于MSDN上的示例)。

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

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

上传的文件:Counterparts.avro

上传的文件:ProductCategorties.avro

上传的文件:SomeOtherFile.avro

所有文件已上传。

但是,尽管文件上传正常,但没有任何语句被打印。

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

编辑:作为对其中一项评论的回应,这是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在我阅读时所做)。

1 个答案:

答案 0 :(得分:0)

假设onAdd = () => { this.setState((prevState) => { const newUser = {} return { users: [...prevState.users, newUser], } }, () => { console.log(this.state.users) }); } 可以正常工作,则可以大大简化您的代码。

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

UploadFiles

方法的结尾是文件已上传且任务完成的那一刻。无需while循环和手动从阵列中删除任务。

它认为即使仅用于日志记录,您甚至不需要返回文件名

要记录所有已完成的消息,只需在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; } 之后写一个日志文件:

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); 作为方法签名(要求c#7.1,请参见this)或将public async Task Main()更改为{{ 1}},否则应用程序将不会等待您的代码完成,因此不会显示任何输出。

另外一种选择是在await Task.WhenAll(tasks);方法的最后添加行Task.WaitAll(tasks);,然后等待输出显示。