在控制台应用程序中同步执行任务 运行
Tasks running synchronously in console application
我的控制台应用程序正在通过 HTTP 执行多个 API 请求。
当 运行 在单线程中运行时,它最多可以处理 8 API 个请求/秒。
正在接收 API 呼叫的服务器有很多空闲资源,因此它应该能够处理超过 8 个/秒。
另外,当我 运行 应用程序的多个实例时,每个实例仍然能够每秒处理 8 个请求。
我尝试了以下代码来并行化请求,但它仍然是 运行s 同步:
var taskList = new List<Task<string>>();
for (int i = 0; i < 10000; i++)
{
string threadNumber = i.ToString();
Task<string> task = Task<string>.Factory.StartNew(() => apiRequest(requestData));
taskList.Add(task);
}
foreach (var task in taskList)
{
Console.WriteLine(task.Result);
}
我做错了什么?
编辑:
我的错误是遍历任务并获得 task.Result,这阻塞了主线程,让我认为它是同步 运行ning。
我最终使用的代码而不是 foreach(taskList 中的 var task):
while (taskList.Count > 0)
{
Task.WaitAny();
// Gets tasks in RanToCompletion or Faulted state
var finishedTasks = GetFinishedTasks(taskList);
foreach (Task<string> finishedTask in finishedTasks)
{
Console.WriteLine(finishedTask.Result);
taskList.Remove(finishedTask);
}
}
可能会发生一些事情。
首先,.net ServicePoint
class 默认情况下允许每个主机最多有 2 个连接。参见 this Stack Overflow question/answer。
其次,您的服务器理论上可能能够处理超过 8 个/秒,但在服务器端可能存在资源限制或其他问题。我 运行 遇到了 API 调用的问题,这些调用理论上应该能够处理比它们实际处理的更多的东西,但由于某种原因设计或实施不当。
@theMayer 有点正确。您对 apiRequest 的调用可能会阻塞并使整个表达式看起来是同步的...
但是...您正在遍历每个任务并调用 task.Result,这将阻塞直到任务完成以便将其打印到屏幕上。因此,例如,除了第一个任务之外的所有任务都可以完成,但是在第一个任务完成之前您不会打印它们,并且您将继续按顺序打印它们。
稍微不同的是,您可以像这样更简洁地重写:
var screenLock = new object();
var results = Enumerable.Range(1, 10000)
.AsParallel()
.Select(i => {
// I wouldn't actually use this printing, but it should help you understand your example a bit better
lock (screenLock) {
Console.WriteLine("Task i");
}
apiRequest(requestedData));
});
没有打印,它看起来像这样:
var results = Enumerable.Range(1, 10000)
.AsParallel()
.Select(i => apiRequest(requestedData));
我的控制台应用程序正在通过 HTTP 执行多个 API 请求。
当 运行 在单线程中运行时,它最多可以处理 8 API 个请求/秒。
正在接收 API 呼叫的服务器有很多空闲资源,因此它应该能够处理超过 8 个/秒。
另外,当我 运行 应用程序的多个实例时,每个实例仍然能够每秒处理 8 个请求。
我尝试了以下代码来并行化请求,但它仍然是 运行s 同步:
var taskList = new List<Task<string>>();
for (int i = 0; i < 10000; i++)
{
string threadNumber = i.ToString();
Task<string> task = Task<string>.Factory.StartNew(() => apiRequest(requestData));
taskList.Add(task);
}
foreach (var task in taskList)
{
Console.WriteLine(task.Result);
}
我做错了什么?
编辑: 我的错误是遍历任务并获得 task.Result,这阻塞了主线程,让我认为它是同步 运行ning。
我最终使用的代码而不是 foreach(taskList 中的 var task):
while (taskList.Count > 0)
{
Task.WaitAny();
// Gets tasks in RanToCompletion or Faulted state
var finishedTasks = GetFinishedTasks(taskList);
foreach (Task<string> finishedTask in finishedTasks)
{
Console.WriteLine(finishedTask.Result);
taskList.Remove(finishedTask);
}
}
可能会发生一些事情。
首先,.net ServicePoint
class 默认情况下允许每个主机最多有 2 个连接。参见 this Stack Overflow question/answer。
其次,您的服务器理论上可能能够处理超过 8 个/秒,但在服务器端可能存在资源限制或其他问题。我 运行 遇到了 API 调用的问题,这些调用理论上应该能够处理比它们实际处理的更多的东西,但由于某种原因设计或实施不当。
@theMayer 有点正确。您对 apiRequest 的调用可能会阻塞并使整个表达式看起来是同步的...
但是...您正在遍历每个任务并调用 task.Result,这将阻塞直到任务完成以便将其打印到屏幕上。因此,例如,除了第一个任务之外的所有任务都可以完成,但是在第一个任务完成之前您不会打印它们,并且您将继续按顺序打印它们。
稍微不同的是,您可以像这样更简洁地重写:
var screenLock = new object();
var results = Enumerable.Range(1, 10000)
.AsParallel()
.Select(i => {
// I wouldn't actually use this printing, but it should help you understand your example a bit better
lock (screenLock) {
Console.WriteLine("Task i");
}
apiRequest(requestedData));
});
没有打印,它看起来像这样:
var results = Enumerable.Range(1, 10000)
.AsParallel()
.Select(i => apiRequest(requestedData));