C# 从列表中查找未完成任务的详细信息

C# 从列表中查找未完成任务的详细信息,c#,async-await,C#,Async Await,我有一个递归下降函数,它将父目录中的所有文件以及任意数量的子目录中的所有文件发送到AWS S3。我有一个5分钟的超时时间,设置为让文件夹中的所有文件被推送到S3,如果超过这个时间,我想取消剩余的任何任务。当我为令牌设置cancel标志时,不管延迟或等待是否达到超时,我希望能够从列表中获取所有未完成的任务,并获取日志记录请求的详细信息。微软表示,任务的和不能被认为是唯一的 如何从任务对象获取创建任务的请求对象 private static void ProcessDirectory(System.

我有一个递归下降函数,它将父目录中的所有文件以及任意数量的子目录中的所有文件发送到AWS S3。我有一个5分钟的超时时间,设置为让文件夹中的所有文件被推送到S3,如果超过这个时间,我想取消剩余的任何任务。当我为令牌设置cancel标志时,不管延迟或等待是否达到超时,我希望能够从列表中获取所有未完成的任务,并获取日志记录请求的详细信息。微软表示,任务的和不能被认为是唯一的

如何从任务对象获取创建任务的请求对象

private static void ProcessDirectory(System.IO.DirectoryInfo di)
{
    int _timeOut = 5 * 60 * 1000;
    foreach (var item in di.GetDirectories())
    {
        ProcessDirectory(item);
    }

    using (Amazon.S3.AmazonS3Client _client = new Amazon.S3.AmazonS3Client())
    {
        System.Threading.CancellationTokenSource _cancellationTokenSource = new System.Threading.CancellationTokenSource();
        System.Collections.Generic.List<System.Threading.Tasks.Task<Amazon.S3.Model.PutObjectResponse>> _responses = new List<System.Threading.Tasks.Task<Amazon.S3.Model.PutObjectResponse>>(1000);
        foreach (var item in di.GetFiles())
        {
            _responses.Add(_client.PutObjectAsync(new Amazon.S3.Model.PutObjectRequest
            {
                BucketName = SiteSettings.Bucket,
                CannedACL = Amazon.S3.S3CannedACL.PublicRead,
                FilePath = item.FullName,
                Key = item.FullName.Replace(SiteSettings.OutputRoot, string.Empty).Replace(@"\", "/")
            }, _cancellationTokenSource.Token));                    
        }
        // Wait 5 Mins + 1 sec
        System.Threading.Tasks.Task.WhenAny(System.Threading.Tasks.Task<Amazon.S3.Model.PutObjectResponse>.WhenAll(_responses)
            , System.Threading.Tasks.Task.Delay(_timeOut)).Wait(_timeOut + 1000);

        _cancellationTokenSource.Cancel(); //Cancel the remaining pushes for this folder.
        foreach (var item in _responses)
        {
            if (!item.IsCompleted)
            {
                //Pull the key value to log
            }
        }
    }
}

您可以在创建每个工作项后为其保存一些唯一的键,然后使用该键进行日志记录。在本例中,我使用item.FullName作为键。此外,为了更好的可读性,我还随意删除了类型之前的长名称空间,希望您不会介意:

private static void ProcessDirectory(System.IO.DirectoryInfo di)
{
    int _timeOut = 5 * 60 * 1000;
    foreach (var item in di.GetDirectories())
    {
        ProcessDirectory(item);
    }

    using (Amazon.S3.AmazonS3Client _client = new Amazon.S3.AmazonS3Client())
    {
        CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
        Dictionary<string, Task<Amazon.S3.Model.PutObjectResponse>> _responses =
            new Dictionary<string, Task<Amazon.S3.Model.PutObjectResponse>>(1000);

        foreach (var item in di.GetFiles())
        {
            // use any unique information about your item here
            var itemName = item.FullName;
            _responses[itemName] = _client.PutObjectAsync(new Amazon.S3.Model.PutObjectRequest
            {
                BucketName = SiteSettings.Bucket,
                CannedACL = Amazon.S3.S3CannedACL.PublicRead,
                FilePath = itemName,
                Key = item.FullName.Replace(SiteSettings.OutputRoot, string.Empty).Replace(@"\", "/")
            }, _cancellationTokenSource.Token);
        }
        // Wait 5 Mins + 1 sec
        Task.WhenAny(Task<Amazon.S3.Model.PutObjectResponse>.WhenAll(_responses.Values)
            ,Task.Delay(_timeOut)).Wait(_timeOut + 1000);

        _cancellationTokenSource.Cancel(); //Cancel the remaining pushes for this folder.
        foreach (var item in _responses)
        {
            if (!item.Value.IsCompleted)
            {
                //Pull the key value to log
                var keyValue = item.Key;
            }
        }
    }
}
你们看,我和字典交换了列表,其中键是文件的全名。因此,如果字典中的某个任务没有在5分钟内完成,您将能够获得未加载的文件名


希望能有所帮助。

如果您将ProcessDirectory更改为异步方法,并且只等待循环中的单个PUT,那么您的代码将更加简单和快速。尝试同时执行eg 100 PUTs将导致100次缓慢上传。对于大文件,一次上载一个文件要比同时上载100个文件快。其他的选择是使用Parallel.For,限制一次可以运行多少并发任务,或者使用DOP>1@PanagiotisKanavos你能解释为什么一个项目的线程速度比多个项目快吗?在我看来,创建线程只是为了创建线程,而不是在前台运行,当cpu有时间到达时,它会被放到后台完成,而不是让上下文和cpu准备好运行代码块。