为每个方法并行执行自定义数量 cores/thread 的两个方法

Execute two methods on custom number of cores/thread for each method in parallel

有没有一种方法可以指定每个方法使用的 Cores/threads 的数量而不阻塞它们。 例子: 我有方法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 建议 post 带有信号量的代码之后,我发现我没有做一些应该做的事情, 第二次使用信号量实现:

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

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

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

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

感谢大家的帮助。我通过 运行ning 两项任务完成了解决方案。我需要 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();
}