我是异步编程的新手,正在尝试将说2个文件并行上传到rest api。每个文件的上传过程包含3个rest调用 1.初始放置:创建文件 2.使用补丁附加数据 3.保存/刷新文件中的数据以将其提交。
所有这些都按顺序工作,但是当我尝试异步执行此操作时,由于异步方法的参数被其他任务覆盖,因此会出现随机故障。
我一直在遵循以下指南:https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/,并尝试遵循类似的策略
private async Task<string> UploadFiles(string year, string month, string filename, string accesstoken, string path)
{
//Initial Put : corresponding to point 1 above in the summary
var method = new HttpMethod("PUT");
url = String.Format("https://someurl/part1/{0}/{1}/{2}?resource=file&recursive=True", year, month, localfilename);
var request = new HttpRequestMessage(method, url)
{
Content = null
};
request.Headers.Add("Authorization", "Bearer " + accesstoken);
var initput = await client.SendAsync(request);
//Append Data :corresponding to point 2 above in the summary
url = String.Format("https://someurl/part1/{0}/{1}/{2}?action=append&position=0", year, month, localfilename);
****Here some code for file details which isn't necessary for this question***
method = new HttpMethod("PATCH");
request = new HttpRequestMessage(method, url)
{
Content = content
};
request.Headers.Add("Authorization", "Bearer " + accesstoken);
var response = await client.SendAsync(request);
long? position = request.Content.Headers.ContentLength;
//Flush Data:corresponding to point 3 above in the summary
url = String.Format("someurl/part1/{0}/{1}/{2}?action=flush&position={3}", year, month, localfilename, position.ToString());
request = new HttpRequestMessage(method, url)
{
Content = null
};
request.Headers.Add("Authorization", "Bearer " + accesstoken);
response = await client.SendAsync(request);
return filename;
}
在调用方中,我使用多个任务来调用它,以便它们同时启动然后等待
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;
}
}
我希望做到这一点(尽管不是以任何特定的顺序,而是在特定的文件中或在任务中的顺序)。
因此,如果我检查Fiddler,我希望:
/part1/2019/02/Counterparts.avro?resource=file&recursive=True
/part1/2019/02/ProductCategories.avro?resource=file&recursive=True
/part1/2019/02/ProductCategories.avro?action=append&position=0
/part1/2019/02/Counterparts.avro?action=append&position=0
/part1/2019/02/ProductCategories.avro?action=flush&position=1664
/part1/2019/02/Counterparts.avro?action=flush&position=30907958
但是我得到了
/part1/2019/02/Counterparts.avro?resource=file&recursive=True
/part1/2019/02/ProductCategories.avro?resource=file&recursive=True
/part1/2019/02/Counterparts.avro?action=append&position=0
/part1/2019/02/Counterparts.avro?action=append&position=0
/part1/2019/02/ProductCategories.avro?action=flush&position=1664
/part1/2019/02/Counterparts.avro?action=flush&position=30907958
因此,如果您看到“ action = append”,那么我会收到2个对口服务的调用,而不是对ProductCategories的调用,因此对ProductCategories的冲洗操作失败,因为首先没有发生附加操作。
基本上发生了什么事,我的异步函数中的参数文件名在任务中被覆盖了。
如何确保2个文件并行处理这3组REST调用,而不覆盖其他任务中的变量
答案 0 :(得分:2)
您对url变量的使用不是线程安全的。我看到它是在您的方法之外定义的,但是随后您可以使用它并在整个方法中对其进行更改。
当您进行两次异步运行时,使用并更改相同的变量将获得竞争条件。