C# 如何验证n个方法是并行执行的?

C# 如何验证n个方法是并行执行的?,c#,task-parallel-library,C#,Task Parallel Library,仅出于知识目的,我如何验证n个方法是并行执行的 Parallel.For(0,10,i=>DoSomething(i)); ... 无效剂量测定法(国际标准) { WriteLine($“Test:{par}”); } 有没有一个测试可以保证DoSomething不是按顺序执行的(如果Console.WriteLine不是一个好的测试,那么什么可以是一个非常简单的测试函数?在您的示例中,这些方法肯定是按顺序执行的,因为.NET控制台将按顺序执行 但是,您可以使用或检查正在运行该方法的线程ID(

仅出于知识目的,我如何验证n个方法是并行执行的

Parallel.For(0,10,i=>DoSomething(i));
...
无效剂量测定法(国际标准)
{
WriteLine($“Test:{par}”);
}

有没有一个测试可以保证DoSomething不是按顺序执行的(如果
Console.WriteLine
不是一个好的测试,那么什么可以是一个非常简单的测试函数?

在您的示例中,这些方法肯定是按顺序执行的,因为.NET控制台将按顺序执行

但是,您可以使用或检查正在运行该方法的线程ID(对于.NET 4.5)

如果在不使用
Thread.Sleep
的情况下运行此调用,您会注意到只会使用几个线程,因为调用将足够快地完成,线程将及时返回到池中,以拾取队列分发的下一个作业

添加睡眠将使线程(模拟工作)延迟足够长的时间,线程池将不得不寻找更多线程,以便及时完成作业

当并行运行任何任务时,很容易检查这些任务是否都在单独的线程中运行。然而,您是否能获得性能优势,将取决于这些线程的工作效率。如您所见,有些操作会调用共享资源上的争用(如写入控制台),并会阻止多个线程同时运行


其他争用源可能是内存分配,例如,如果您的线程都在大量分配和取消分配内存,那么它们最终可能会花费大量时间等待内存管理器的轮到它们。这将限制您将实现的实际并行度

不知道我是否理解你想做什么。你可以数一数

Parallel.For(0, 10, i => DoSomething(i));

...

private static int parallelCounter = 0;
private static object counterLockObject = new Object();
void DoSomething(int par)
{
    int myCounter;
    lock(counterLockObject)
    {
        myCounter = ++parallelCounter;
    }
    try
    {
        // you probably need something that takes more time to
        // see anything executing in parallel
        Console.WriteLine("Current number of parallel threads: {0}", myCounter);
    }
    finally
    {
        lock(counterLockObject)
        {
            parallelCounter--;
        }        
    }
}

您可以使用以下代码检查并行执行的方法数:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ParallelMethodsCounter
{
    class Program
    {
        public static int _parallelCounter = 0;
        public static int _maxParallelExecutionsCount = 0;

        static void Main(string[] args)
        {
            Parallel.For(0, 10, i => DoSomething(i));
            Console.WriteLine("MAX PARALLEL EXECUTIONS: {0}", _maxParallelExecutionsCount);
        }

        public static void DoSomething(int par)
        {
            int currentParallelExecutionsCount = Interlocked.Increment(ref _parallelCounter);
            InterlockedExchangeIfGreaterThan(ref _maxParallelExecutionsCount, currentParallelExecutionsCount, currentParallelExecutionsCount);
            Console.WriteLine("Current parallel executions: {0}", currentParallelExecutionsCount);
            try
            {
                //Do your work here
            }
            finally
            {
                Interlocked.Decrement(ref _parallelCounter);
            }
        }

        public static bool InterlockedExchangeIfGreaterThan(ref int location, int comparison, int newValue)
        {
            int initialValue;
            do
            {
                initialValue = location;
                if (initialValue >= comparison) return false;
            }
            while (Interlocked.CompareExchange(ref location, newValue, initialValue) != initialValue);
            return true;
        }
    }
}

但是请记住,Parallel.For不会尝试并行执行太多,因为它使用线程池,并且默认情况下使用的线程数等于处理器核心数。在我的四核机器上,我通常得到2-4次并行执行,有时最多执行5次(当然这里没有严格的限制)。

让其中一个任务运行更长时间,比如
if(par==1)Thread.Sleep(1000);Console.Write…
您可以尝试故意创建一个竞争条件,看看是否发生了这种情况。为什么不尝试打印
当前时间
?为什么要对此进行测试?确保第三方物流正常运行或识别
剂量测量中的问题
?在任何情况下,.NET性能计数器都包括线程池的指标,您可以使用这些指标来检查有多少线程正在运行,例如使用性能监视器。还要注意,
Paraller.For
是一个阻塞调用。您将无法检查来自同一线程的计数器。此外,使用多少线程取决于很多因素,包括可用内核的数量。在双芯机器上,当您可以
互锁时,您将找不到10条活动线程。增量
互锁。减量
?那么一个
int
字段就足够了。这并不重要,不是吗?为工作选择正确的工具并不重要,直到它真的重要。答案在事实上没有错,但如果有更好的方法做某事,那就值得一提(这里“更好”可以通过字段和指令的数量客观地量化)。事实上,我收回这一点:这个答案在事实上有问题。您的
parallelCounter++
应该是
++parallelCounter
。否则,
myCounter
将以1为界。好的,我修复计数器。我不太喜欢联锁,因为我可能从来没有真正的应用程序。您开始使用interlocked,并且必须在下次触摸代码时将其更改为常规锁。但所有这些并不是真正的重点。这只是计算并行线程的一种方法,甚至不确定这是否是OP要求的。实施细节与此无关。不过还是要感谢你的反馈。为了保持无锁状态,这个“互锁的任何东西”的实现过于复杂,真是太有趣了,我不得不为它的纯粹娱乐价值投上一票。我发现长方法名称上的
Interlocked
前缀有点误导,因为与其他“true”Interlocked方法不同,它不能保证内存隔离(在这种特殊情况下并不重要),但在其他情况下,这非常酷。
using System;
using System.Threading;
using System.Threading.Tasks;

namespace ParallelMethodsCounter
{
    class Program
    {
        public static int _parallelCounter = 0;
        public static int _maxParallelExecutionsCount = 0;

        static void Main(string[] args)
        {
            Parallel.For(0, 10, i => DoSomething(i));
            Console.WriteLine("MAX PARALLEL EXECUTIONS: {0}", _maxParallelExecutionsCount);
        }

        public static void DoSomething(int par)
        {
            int currentParallelExecutionsCount = Interlocked.Increment(ref _parallelCounter);
            InterlockedExchangeIfGreaterThan(ref _maxParallelExecutionsCount, currentParallelExecutionsCount, currentParallelExecutionsCount);
            Console.WriteLine("Current parallel executions: {0}", currentParallelExecutionsCount);
            try
            {
                //Do your work here
            }
            finally
            {
                Interlocked.Decrement(ref _parallelCounter);
            }
        }

        public static bool InterlockedExchangeIfGreaterThan(ref int location, int comparison, int newValue)
        {
            int initialValue;
            do
            {
                initialValue = location;
                if (initialValue >= comparison) return false;
            }
            while (Interlocked.CompareExchange(ref location, newValue, initialValue) != initialValue);
            return true;
        }
    }
}