在控制台应用程序中同步执行任务 运行

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));