【问题标题】:Task management in C# with IIS hosting WCF service使用 IIS 托管 WCF 服务的 C# 中的任务管理
【发布时间】:2015-10-21 17:47:01
【问题描述】:

我在 IIS 中托管了 32 位版本的 WCF 服务。其中,我使用以下方法创建任务以并行执行我的操作(进行数据库计算或对第三方进行外部调用)。

   List<Task> taskList = new List<Task>();
    Task parentTask = Task.Factory.StartNew(() =>
    {
        for (int i = 0; i <= 5; i++)
        {
            var task = new Task(() => Do(), TaskCreationOptions.AttachedToParent);
            taskList.Add(task);
        }
    });


    foreach (Task t in taskList)
    {
        t.Start();
    }

    parentTask.Wait(20000);

使用上面的代码,我创建了大约 140 个任务,对我的服务提出了一个请求。我的应用程序每秒大约有 10 个请求。

我面临的问题是,在我的父线程等待执行繁重的操作时,大多数任务都没有执行,然后任务没有获得足够的 CPU 意味着不调用并行任务。

我只想知道处理多线程的最佳方式。我遇到过很多文章,Task.Factory.StartNew 总是使用线程池概念,为什么我的任务在高并发请求的情况下启动和运行需要超过 20 秒的时间。

在这种情况下,我假设所有操作都在父级等待之前完成。这是取消任务而不是等待的最佳方式吗?

32 位应用程序和 64 位应用程序对带有任务管理的 .Net framework 4.0 有重大影响吗?

提前致谢!!

【问题讨论】:

  • 没有看得太仔细,但也许用 Task.WaitAll(taskList) 替换 parentTask.Wait(20000) 是你所追求的。在这种情况下,可能不需要您的 parentTask 实例。

标签: c# multithreading wcf task-parallel-library task


【解决方案1】:

总有“最好的方法”。在你的情况下尝试

taskList.WaitAll();而不是 parentTask.Wait(20000);

【讨论】:

    【解决方案2】:

    关于你的第二个问题:

    32 位应用程序和 64 位应用程序对带有任务管理的 .Net framework 4.0 有重大影响吗?

    答案是否定的。任务在线程池线程上执行。 CPU 一次可以执行一个线程,无论它运行的是 32 位还是 64 位进程。线程池的大小可以调整,但不推荐。 .NET 框架通过复杂的计算来确定线程池的大小,该计算基于 CPU/内核的数量、时钟速度和其他一些参数。

    同时执行太多线程效率不高,因为线程之间的管理和切换需要资源。如果你让一堆 CPU 密集型线程全部排队,那么只需在它们之间来回切换就会消耗大量 CPU 时间,并且永远无法完成任何工作(有点像当你有 7 个项目经理每隔10 分钟要求状态更新),随着请求更多的工作而导致创建更多线程,直到您的服务器以 100% 的速度运行并停止。

    【讨论】:

      【解决方案3】:

      既然父任务应该等待子任务,那么您应该使用 Task 类的 WaitAll 方法,该方法等待所有提供的 Task 对象完成执行。

      创建了示例程序来演示相同的内容:

      using System;
      using System.Threading.Tasks;
      using System.Collections.Generic;
      
      public class Program
      {
          public static void Main()
          {   
              Console.WriteLine("Starting Parent Task");
               List<Task> taskList = new List<Task>();
               Task parentTask = Task.Factory.StartNew(() =>
               {
                  for (int i = 0; i <= 5; i++)
                  {
                      var task = new Task(() => Console.WriteLine("Task Running : " + Task.CurrentId), TaskCreationOptions.AttachedToParent);
                      taskList.Add(task);
                  }
      
                  foreach (Task t in taskList)
                  {
                      t.Start();
                  }
      
                  Task.WaitAll(taskList.ToArray());
      
               });
      
      
              Console.WriteLine("Parent Task Ending");
      
          }
      }
      

      创建this dotnet fiddle。您可以在小提琴中检查它的输出。

      【讨论】:

        【解决方案4】:

        我猜你已经读过这篇文章 (https://msdn.microsoft.com/en-us/library/dd997417.aspx)。如果您不使用附加任务方法(异常和取消传播)提供的任何功能,您可以这样做,因为 Atom 只是建议 taskList.WaitAll(20000)。但请记住,在此 Wait() 完成后,如果您没有明确实施取消,您的任务仍在运行。

        Do() 是什么也很重要。任务正在使用 ThreadPool,您可以管理其中的线程数。 You can specify the number of threads 在里面。如果你的 Do() 是计算,你总是使用 worker 线程。但如果在此调用中您使用另一个服务,您应该异步执行此操作。这样,您将使用 I/O 完成端口 和适当的 I/O 线程,这几乎不会消耗任何系统资源。要异步运行服务调用,您可以使用带有任务结果或 Begin/End+IAsyncResult 的客户端方法的异步版本。在第二种情况下,您可以使用TaskFactory.FromAsync 将其转换为任务。

        【讨论】:

          猜你喜欢
          • 2022-12-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多