我有项目列表,对于我想要调用UploadChunkToServer方法的每个项目,但是并行。列表中始终只有4个项目。
if (DataQueue.Count == NumberofChunksToRead)
{
DataQueue.ToList().ForEach(Chunk =>
{
UploadChunkToServer(Chunk);
});
}
以上是我在方法中的代码调用,方法签名如下。
private void UploadChunkToServer(UserCustomFile Chunk)
{
var client = new RestClient(Helper.GetServerURL());
var request = new RestRequest("api/fileupload/savechunk", Method.POST);
request.AddHeader("Content-type", "application/json");
request.RequestFormat = RestSharp.DataFormat.Json;
request.AddJsonBody(Chunk);
client.ExecuteAsync(request, response =>
{
if (response.StatusCode != System.Net.HttpStatusCode.OK)
{
throw new Exception(response.ErrorMessage);
}
else
{
ChunkStatuses.Add(Chunk.ChunkID);
}
});
}
我试图添加异步运算符但没有运气。有什么想法可以实现吗?
答案 0 :(得分:2)
也许您可以在具体的情况下使用Parallel和ForEach:
Parallel.ForEach(DataQueue.ToList(), Chunk =>
{
UploadChunkToServer(Chunk);
});
答案 1 :(得分:0)
您可以执行以下操作:
var tasks = new List<Task<bool>>();
DataQueue.ToList().ForEach(chunk =>
{
tasks.Add(Task.Run(() => UploadChunkToServer(chunk)));
});
await tasks.WhenAll();
但你应该改变UploadChunkToServer
以返回一些东西; bool
表示上传是否成功。应该避免void Tasks
,双关语...
更新:正如TheBoyan的answer所指出的那样,你可以简化这种制作UploadChunkToServer
异步,但我仍然建议你回复一些事情,这样你就能抓住任务供以后处理。如果它是一个火灾和遗忘的场景,这不是必要的:
var tasks = new List<Task<bool>>();
DataQueue.ToList().ForEach(chunk =>
{
tasks.Add(UploadChunkToServer(chunk));
});
await tasks.WhenAll();
而UploadChunkToServer
看起来像是:
private async Task<bool> UploadChunkToServer(UserCustomFile Chunk)
{
var client = new RestClient(Helper.GetServerURL());
var request = new RestRequest("api/fileupload/savechunk", Method.POST);
request.AddHeader("Content-type", "application/json");
request.RequestFormat = RestSharp.DataFormat.Json;
request.AddJsonBody(Chunk);
return await client.ExecuteAsync(request, response =>
{
if (response.StatusCode != System.Net.HttpStatusCode.OK)
{
throw new Exception(response.ErrorMessage);
}
else
{
ChunkStatuses.Add(Chunk.ChunkID);
return true;
}
});
}
答案 2 :(得分:0)
您的问题有点不清楚,我认为您混淆了异步和并行,这在C#中不一定相同。
C#中有两种类型的异步:
I / O绑定(通过网络读/写等)
长时间运行(高处理等)
你的是一个I / O绑定操作,所以它通过在完成后通知调用者(通过在后台提供状态机)来工作。将其视为基于事件的模式。
如果您已经拥有API或库提供的[YourMethodName] Async方法,或者TaskCompletionSource自己实现它,那么您最好处理它的方式就是等待。请注意,您不一定需要并行线程来实现它(通过运行Task.Run或其他方式),框架(或实现该方法的方法在[YourMethodName] Async的情况下为您提供)任务已经为你完成了。
所以,如果你想让你的方法异步运行client.ExecuteAsync
,假设ExecuteAsync返回Task
。
在您的代码中,您可以这样做:
// add async keyword to notify that you are awaitng int he method
// perhaps also change the void to Task
private async Task UploadChunkToServer(UserCustomFile Chunk)
{
var client = new RestClient(Helper.GetServerURL());
var request = new RestRequest("api/fileupload/savechunk", Method.POST);
request.AddHeader("Content-type", "application/json");
request.RequestFormat = RestSharp.DataFormat.Json;
request.AddJsonBody(Chunk);
//add await operator to make this part run acync
return await client.ExecuteAsync(request, response =>
{
if (response.StatusCode != System.Net.HttpStatusCode.OK)
{
throw new Exception(response.ErrorMessage);
}
else
{
ChunkStatuses.Add(Chunk.ChunkID);
}
});
}
然后进入你的调用堆栈:
if (DataQueue.Count == NumberofChunksToRead)
{
DataQueue.ToList().ForEach(Chunk =>
{
await UploadChunkToServer(Chunk);
});
}
您也可以考虑使用“任务”返回结果,以便您可以关注进度或查看已上传的内容等。
如果您想在并行中运行该方法,则使用 Parallel Foreach 的上一个答案将完成此任务。虽然,我认为在这种情况下执行此操作并不好,因为您有一个I / O绑定操作。你基本上要做的是运行一个长时间运行的任务,除了大部分时间之外什么都不做。在4核心处理器的情况下,你生成4个线程,这意味着你只需等待就可以占用所有这些线程。你一直在做的事情就是在等待。
答案 3 :(得分:-1)
你不能这样做,因为ForEach的参数是ForEach调用的一个不同的函数,而不是异步的功能的一部分 - 但实际的解决方案是不使用ForEach - foreach实际上有点短并没有这个问题
if (DataQueue.Count == NumberofChunksToRead)
{
forach(var Chunk in DataQueue.ToList())
{
await UploadChunkToServer(Chunk);
}
}