【问题标题】:Execute two methods on custom number of cores/thread for each method in parallel对每个方法的自定义核心/线程数并行执行两个方法
【发布时间】:2018-08-25 09:59:36
【问题描述】:

有没有办法指定每个方法使用的核心/线程数并且不阻塞它们。 例子: 我有方法A和方法B。 方法 A 会被调用 50 次,方法 B 也会被调用。

假设我有一个 16 核的 CPU。 我想将其委托给方法 A 它将并行使用 2 个线程,而方法 B 将使用 4 个线程并且不会阻塞它们。 我尝试过使用信号量,但在任务执行后它们会阻塞和释放。

这里是一些示例代码: 注意:threadService 方法只是调用 Thread.Sleep 3 秒

static void Main(string[] args)
    {
        ThreadService threadService = new ThreadService();

        for (int i = 0; i < 5; i++)
        {
            Task t = Task.Run(() => threadService.RunFirstMethod());
        }

        for (int i = 0; i < 5; i++)
        {
            Task t = Task.Run(() => threadService.RunSecondMethod());
        }

        Console.ReadLine();
    }

也许这不是一个好主意...?任何帮助或建议将不胜感激。 谢谢。

信号量的第一次尝试(不行):

static void Main(string[] args)
    {
        ThreadService threadService = new ThreadService();

        Semaphore semaphoreFirstMethod = new Semaphore(2, 2);
        for (int i = 0; i < 5; i++)
        {
            semaphoreFirstMethod.WaitOne();
            Task t = Task.Run(() => threadService.RunFirstMethod()).ContinueWith(s => semaphoreFirstMethod.Release());
        }

        Semaphore semaphoreSecondMethod = new Semaphore(2,2);
        for (int i = 0; i < 5; i++)
        {
            semaphoreSecondMethod.WaitOne();
            Task t = Task.Run(() => threadService.RunSecondMethod()).ContinueWith(s => semaphoreSecondMethod.Release());
        }
        Console.ReadLine();
    }

结果如下:

   2018-08-25 15:34:17.7259 INFO RunFirstMethod()
2018-08-25 15:34:17.7259 INFO RunFirstMethod()
2018-08-25 15:34:19.7691 INFO RunFirstMethod()
2018-08-25 15:34:19.7691 INFO RunFirstMethod()
2018-08-25 15:34:21.7775 INFO RunFirstMethod()
2018-08-25 15:34:21.7775 INFO RunSecondMethod()
2018-08-25 15:34:21.7775 INFO RunSecondMethod()
2018-08-25 15:34:23.8053 INFO RunSecondMethod()
2018-08-25 15:34:23.8053 INFO RunSecondMethod()
2018-08-25 15:34:25.8211 INFO RunSecondMethod()

在@mjwills 建议使用 sempahores 发布代码后,我发现我没有做应有的事情, 信号量的第二次实现:

static void Main(string[] args)
    {
        ThreadService threadService = new ThreadService();

        Task.Run(() =>
        {
            Semaphore semaphore = new Semaphore(2, 2);
            for (int i = 0; i < 5; i++)
            {
                semaphore.WaitOne();
                Task t = Task.Run(() => threadService.RunFirstMethod()).ContinueWith(s => semaphore.Release());
            }
        });

        Task.Run(() =>
        {
            Semaphore semaphore = new Semaphore(2, 2);
            for (int i = 0; i < 5; i++)
            {
                semaphore.WaitOne();
                Task t = Task.Run(() => threadService.RunSecondMethod()).ContinueWith(s => semaphore.Release());
            }
        });
        Console.ReadLine();
    }

第二个结果(对我来说没问题):

    2018-08-25 15:36:01.0845 INFO RunSecondMethod()
2018-08-25 15:36:01.0855 INFO RunFirstMethod()
2018-08-25 15:36:02.0863 INFO RunFirstMethod()
2018-08-25 15:36:03.0783 INFO RunSecondMethod()
2018-08-25 15:36:03.1386 INFO RunSecondMethod()
2018-08-25 15:36:03.1386 INFO RunFirstMethod()
2018-08-25 15:36:04.0938 INFO RunFirstMethod()
2018-08-25 15:36:05.0877 INFO RunSecondMethod()
2018-08-25 15:36:05.1547 INFO RunSecondMethod()
2018-08-25 15:36:05.1677 INFO RunFirstMethod()

【问题讨论】:

  • 你能举个例子吗?我无法理解您的要求:/
  • 你的方法实际上会做什么?计算、从一些外部资源(数据库、网络服务等)加载数据?
  • @Fabio 从外部资源加载数据并处理它们并发布
  • 从外部资源加载数据不需要多线程。您可以在一个线程上“同时”加载数据(当您加载数据时,您的线程什么都不做 - 只等待响应 - 这将浪费资源。然后对于处理数据,您可以使用Task Parallel Library (TPL)
  • @Fabio 是的,但在我的情况下,每个线程实际上是独立的,每个线程都会加载、处理不同的数据。每个人都会为特定的客户做特定的工作

标签: c# multithreading task-parallel-library


【解决方案1】:

感谢大家的帮助。我通过运行两个任务完成了解决方案。我需要 2 种方法来并行运行并控制每个方法的线程数) 线程数由信号量控制。 示例:

static void Main(string[] args)
{
    ThreadService threadService = new ThreadService();

    Task.Run(() =>
    {
        Semaphore semaphore = new Semaphore(2, 2);
        for (int i = 0; i < 5; i++)
        {
            semaphore.WaitOne();
            Task t = Task.Run(() => threadService.RunFirstMethod()).ContinueWith(s => semaphore.Release());
        }
    });

    Task.Run(() =>
    {
        Semaphore semaphore = new Semaphore(2, 2);
        for (int i = 0; i < 5; i++)
        {
            semaphore.WaitOne();
            Task t = Task.Run(() => threadService.RunSecondMethod()).ContinueWith(s => semaphore.Release());
        }
    });
    Console.ReadLine();
}

【讨论】:

    【解决方案2】:

    最简单的方法是添加一些调度逻辑,根据线程逻辑索引决定执行哪个方法:

    var threadService = new ThreadService();
    Parallel.For(
        0, 6,
        index =>
        {
            if (index < 4)
                threadService.RunFirstMethod();
            else
                threadService.RunSecondMethod();
        });
    

    但是,这并不能保证一个方法将在同一个核心上独占执行。要实现这一点,您需要指定线程-CPU 亲和性,这对于 .NET 来说有点棘手,因为它在系统线程之上使用自己的线程,这些线程只是可以应用 CPU 亲和性的线程。这是good article,它解释了如何通过外部调用来完成这项工作。

    【讨论】:

    • 是的,我从一开始就采用这种方法,但我不知道我需要为这些方法执行多少任务,可能是第一个 10 个任务,第二个 200 个任务这很棘手,我希望同时执行第一种方法的 3 个任务和第二种方法的 4 个任务(仅作为示例)。我已经用信号量更新了这个问题。 (第二种方法),它实现了我真正想要的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多