C# 如何从List.ForEach C进行异步调用#
我有一个项目列表,对于每个项目,我都想调用UploadChunkToServer方法,但要并行。列表中始终只有4项C# 如何从List.ForEach C进行异步调用#,c#,asynchronous,C#,Asynchronous,我有一个项目列表,对于每个项目,我都想调用UploadChunkToServer方法,但要并行。列表中始终只有4项 if (DataQueue.Count == NumberofChunksToRead) { DataQueue.ToList().ForEach(Chunk => { UploadChunkToServer(Chunk); }); } 上面是我在方法中的代码调用,方法签名如下 private void UploadChunkToSe
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);
}
});
}
我曾尝试添加异步运算符,但没有成功。您对如何实现这一目标有何想法?也许您可以具体利用和使用:
Parallel.ForEach(DataQueue.ToList(), Chunk =>
{
UploadChunkToServer(Chunk);
});
您可以执行以下操作:
var tasks = new List<Task<bool>>();
DataQueue.ToList().ForEach(chunk =>
{
tasks.Add(Task.Run(() => 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;
}
});
}
private async Task UploadChunkToServer(UserCustomFile Chunk)
{
var client=new RestClient(Helper.GetServerURL());
var request=new RestRequest(“api/fileupload/savechunk”,Method.POST);
AddHeader(“内容类型”、“应用程序/json”);
request.RequestFormat=RestSharp.DataFormat.Json;
AddJsonBody(Chunk);
return wait client.ExecuteAsync(请求、响应=>
{
if(response.StatusCode!=System.Net.HttpStatusCode.OK)
{
抛出新异常(response.ErrorMessage);
}
其他的
{
chunkstatus.Add(Chunk.ChunkID);
返回true;
}
});
}
您的问题有点不清楚,我认为您混淆了异步和并行,这在C#中不一定相同
C#中有两种类型的异步:
- I/O绑定(通过网络读取/写入等)
- 长时间运行(高处理等)
client.ExecuteAsync
,则假定ExecuteAsync返回任务。
在代码中,可以执行以下操作:
// 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个线程,这意味着您只需等待就可以占用所有线程。您已经在做的事情首先需要等待。您不能这样做,因为ForEach的参数是ForEach调用的不同函数,而不是异步函数的一部分-但是-实际的解决方案是不使用ForEach-ForEach实际上稍微短一点,没有这个问题
if (DataQueue.Count == NumberofChunksToRead)
{
forach(var Chunk in DataQueue.ToList())
{
await UploadChunkToServer(Chunk);
}
}
我曾尝试添加异步运算符,但没有运气没有运气意味着什么?编译错误?行为没有什么不同?还有什么?通常,异步调用某个任务与并行执行某个任务不同(在您的情况下,这会导致服务器上的并行化)。并行+IO绑定任务=有点浪费,由于UploadChunkToServer
返回void
,因此调用方无法处理任务,因此可能会带来不便。这是一种可能性(我的解释),OP希望在所有任务完成后,在所有
或类似任务时使用某种类型的。如果这是一个火灾和遗忘的场景,那么它应该是好的。就像我在回答中说的,它有点宽泛,我不确定OP想要实现什么。但是,如果您想等待调用堆栈中的上层,您可以将UploadChunkToServer更改为返回任务。(更新了答案)
if (DataQueue.Count == NumberofChunksToRead)
{
forach(var Chunk in DataQueue.ToList())
{
await UploadChunkToServer(Chunk);
}
}