c# - 如何找出哪个任务已完成
问题描述
我有一个异步代码可以将目录中的所有文件上传到 API。它工作正常,但我想跟踪哪个文件已上传并想要记录,以便我可以进行一些状态检查。
我一直在关注这个指南,也是这个。第一个为每个文件和第二个链接创建明确的任务,只讨论显示剩余的任务数量。另一方面,我想找出哪个任务已完成,将其打印到日志中并继续等待,直到没有要上传的文件为止。我正在使用 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
所有文件已上传。
但是,尽管文件上传一切正常,但没有打印任何语句。
如何让它们打印?我只是不想对所有文件都有一个通知,我真的很想知道上传了哪个文件的状态。
编辑:作为对其中一条评论的回应,这里是 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 在我阅读时会这样做)。
解决方案
假设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,请参阅此内容)或更改await Task.WhenAll(tasks);
为,Task.WaitAll(tasks);
否则应用程序将不会等待您的代码完成,因此不会显示输出。
Console.ReadKey();
另外一个选项是在方法的最后添加该行Main
并等待输出显示。
推荐阅读
- laravel - Laravel 项目 - 更新 .vue 文件时,更改不会实时显示
- visio - Visio 组织结构图 - 格式和数字通过
- python - 如何设置 QCheckBox 指标的拉伸因子?
- unit-testing - 如何为 Spring Boot 单元测试排除 Spring Security
- python - Google AI Platform XGBoost - 本地预测有效但在线预测无效
- kubernetes - Kubernetes Deployment 充分利用了 cpu 和内存,而不会给它带来压力
- vim - 在 Vim 中设置默认窗口以打开所有文件/缓冲区
- python - Python脚本到django html输出
- python - 在 O(1) 时间内从集合中选择一个随机元素
- google-sheets - 如何在不复制粘贴的情况下在 Google 表格的单元格中重复使用相同的公式