c# - 带有从多个任务调用的参数的异步方法导致冲突
问题描述
我是异步编程的新手,我正在尝试将 2 个文件并行上传到一个 rest api。每个文件的上传过程包括 3 个休息调用 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 次针对 Counterparts 的调用,但没有针对 ProductCategories 的调用,因此 ProductCategories 上的刷新操作失败,因为它首先没有发生追加。
基本上发生的事情是我的异步函数中的参数文件名在任务中被覆盖。
如何确保这 2 个文件并行操作这组 3 个 REST 调用,而不覆盖其他任务中的变量
解决方案
您对 url 变量的使用不是线程安全的。我看到它是在您的方法之外定义的,但是您使用它并在整个方法中更改它。
当您有两次异步运行时,使用和更改相同的变量您会得到竞争条件。
推荐阅读
- swiftui - 应用程序在模拟器和预览中启动,但不在真正的 iPhone 或 iPad 上
- javascript - 如何从 Javascript 或 TypeScript 访问所有 selenium 功能?
- azure - 无法对嵌套资源执行请求的操作。找不到父资源“****.io”
- mql4 - 如何使Break even在一个条目中多次触发
- java - 有没有办法在 JLabel 中为字符串中的字符加下划线?
- excel - 此代码的 2016 版本是什么?(运行时错误 5)
- nginx - nginx http 重定向到本地主机
- python - Docker - 在可执行 Python 脚本上导入本地模块
- angular - 在打字稿中使用别名导入特定类型
- c# - 如何创建 Xamarin.Forms 自定义渲染器,其中渲染器基类使用泛型?