【问题标题】:Parent child task - child task takes time to create C# (Performance concern)父子任务 - 子任务需要时间来创建 C#(性能问题)
【发布时间】:2015-08-07 11:32:50
【问题描述】:

我正在使用以下代码来创建父子任务。父任务的工作只是等待 5 秒,子任务执行并将结果存储在共享资源中。 我已标记子任务需要时间。

其实我不知道创建子线程并开始并行执行的内部机制?

是否有任何我可以知道的文档或是否有任何其他最佳方式来实现父子概念?

List<Task> taskList = new List<Task>();

Task parentTask = Task.Factory.StartNew(() =>
{
    int index = 0;
    for (int i = 0; i < 10; i++)
    {
        var task = new Task(() => PrintHello(), TaskCreationOptions.AttachedToParent);
        taskList.Add(task);
        index++;
    }
    foreach (Task task in taskList)
    {
        task.Start();
    }
});

//Wait Parent Task.
parentTask.Wait(5000);

编辑:

应用程序太重(平均每秒 5 个请求),它应该在 5 秒内给出响应。

我正在使用任务以获得更好的性能。 除了并行任务还有其他方法吗?

【问题讨论】:

  • 任务不是线程。您不一定要在这里创建一个新线程。线程没有父级。任务可以有父项。
  • 您要解决的实际问题是什么?为什么要在任务之间建立父子关系?为什么要创建冷任务?几乎可以肯定有更好的方法来解决实际问题。例如,使用Parallel.Invoke 或使用Task.WhenAll 等待一系列实时任务完成
  • @Gusdor - 你是对的。我的意思是儿童任务需要时间。我从stackoverflow.com/questions/13429129/task-vs-thread-differences 发现的线程和任务不同。
  • 查看 System.ComponentModel.BackgroundWorker
  • @AdamFinley BackgroundWorker 已经过时并且只适用于 WinForms 应用程序。它不能在不同任务之间创建任何类型的关系、执行延续等。它与调用Task.Run 并使用Progress 对象报告事件本质上是一样的,只是有组件开销并且无法组合多个操作

标签: c# multithreading task


【解决方案1】:

从 cmets 看来,每个 WCF 请求都需要来自 10 多个外部服务的响应。在这种情况下,最好异步调用每个服务,并使用await Task.WhenAll(tasks); 等待所有生成的任务完成,例如:

public async Task CallManyMethods(string someData)
{ 
    var tasks=new []{
        CallSvc1Async(someData),
        CallSvc2Async(someData),
    }
    var results=await Task.WhenAll(tasks);
    ...
    //Unpack the results and keep processing them
}

public async Task<string> CallSvc1Async(string someData)
{
    var response=await _svc1Proxy.GetStuffAsync(someData);
    //build a result from the response
    return result;
}

public async Task<string> CallSvc2Async(string someData)
{
    var url=....
    var json=await _httpClient.GetStringAsync(url);
    ....
    return result;
}

所有方法返回字符串仅用于演示目的。

每个方法都会将调用发送到外部服务,然后释放其线程,直到收到响应。这样,线程不会被阻塞等待响应,总等待时间仅由最慢的外部服务决定。

CallManyMethods 也不会阻止。当await Task.WhenAll 被执行时,正在执行的线程将被释放。所有调用完成后,将在 await 行之后继续执行。

结果是不需要创建父任务和子任务,因为 TPL 已经可以处理这种情况。开销很小,因为没有线程阻塞等待外部服务完成。

这意味着少量的线程可以处理大量的请求。

【讨论】:

  • 如果他正在执行 IO 密集型而不是 CPU 密集型操作,那么异步 IO 绝对是一种可行的方法。
  • @Panagiotis Kanavos - 感谢您的回答!你是对的,我可以使用方法,但我认为,Task.WhenAll(tasks) 在执行所有异步方法时执行。如果异步方法花费的时间超过 5 秒,那么我不想等待该异步方法并希望继续使用主线程。
【解决方案2】:

我会引用@PanagiotisKanavos - 没有理由让启动任务会触发其余部分。您可能遇到了线程池饥饿的问题-您一次只能创建这么多线程-之后您将不得不等待创建新线程;你也没有检查任务是否会完成(从可靠性的角度来看这不是很好)

parentTask.Wait(5000);

将只等待 5 秒并继续 - parentTask 不会被杀死 - 它返回一个布尔值,告诉您任务是否及时完成,但如果任务被新线程触发,线程仍将运行.

如何在执行一些冗长操作的 Web 服务上强制实现低延迟和可靠性:

  1. 将传入请求持久化到持久存储(数据库、云等)中
  2. 创建将从队列中获取记录并执行它们的批处理应用程序(窗口服务)

如果您的客户需要这种冗长操作的结果,您只有一个选择 - 扩展(网络场/云)。

另请注意,更多线程并不等于更好的性能 - 线程非常适合等待 IO 操作,或者如果您有问题的盒子上有多个内核,但如果没有 IO 操作并且只有一个内核,那么您就是实际上让你的代码变慢了。

【讨论】:

  • 应用服务器有 8 核和 16 GB RAM。是的,所有 10 到 12 个任务都没有 IO 操作,但我希望所有任务都应该并行、快速运行并在 4 到 5 秒内返回每个任务结果。还有其他的并行方式吗?
【解决方案3】:

我建议您参考以下可能解决您问题的组件。

Octopus.TaskTree

您可以灵活地await 处理父任务,以串行或并发方式启动子任务。

请参考给出的代码 sn-p 可能会让您清楚地了解组件的用途。

【讨论】:

    猜你喜欢
    • 2012-06-08
    • 1970-01-01
    • 2019-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多