When是Parallel.调用有用

本文关键字:有用 调用 Parallel When | 更新日期: 2023-09-27 18:06:15

我正在深入学习4.0框架中的Parallel类,并试图了解它何时有用。首先,在查看了一些文档之后,我尝试执行两个循环,一个使用Parallel.Invoke,另一个顺序如下:

static void Main()
{
    DateTime start = DateTime.Now;
    Parallel.Invoke(BasicAction, BasicAction2);
    DateTime end = DateTime.Now;
    var parallel = end.Subtract(start).TotalSeconds;
    
    start = DateTime.Now;
    BasicAction();
    BasicAction2();
    end = DateTime.Now;
    var sequential = end.Subtract(start).TotalSeconds;
    
    Console.WriteLine("Parallel:{0}", parallel.ToString());
    Console.WriteLine("Sequential:{0}", sequential.ToString());
    Console.Read();
}
static void BasicAction()
{
    for (int i = 0; i < 10000; i++)
    {
        Console.WriteLine("Method=BasicAction, Thread={0}, i={1}", Thread.CurrentThread.ManagedThreadId, i.ToString());
    }
}
static void BasicAction2()
{
    for (int i = 0; i < 10000; i++)
    {
       Console.WriteLine("Method=BasicAction2, Thread={0}, i={1}", Thread.CurrentThread.ManagedThreadId, i.ToString());
    }
}

这里的执行时间没有明显的差异,还是我错过了重点?它对web服务的异步调用更有用还是…?

EDIT:我用Stopwatch删除了DateTime,通过简单的加法操作删除了对控制台的写入。

UPDATE - Big Time Difference Now:谢谢你帮我解决了Console

的问题
static void Main()
{
    Stopwatch s = new Stopwatch();
    s.Start();
    Parallel.Invoke(BasicAction, BasicAction2);
    s.Stop();
    var parallel = s.ElapsedMilliseconds;
    s.Reset();
    s.Start();
    BasicAction();
    BasicAction2();
    s.Stop();
    var sequential = s.ElapsedMilliseconds;
    
    Console.WriteLine("Parallel:{0}", parallel.ToString());
    Console.WriteLine("Sequential:{0}", sequential.ToString());
    Console.Read();
}
static void BasicAction()
{
    Thread.Sleep(100);
}
static void BasicAction2()
{
    Thread.Sleep(100);
}

When是Parallel.调用有用

你正在做的测试是毫无意义的;你在测试一些你不能并行执行的事情,如果你并行执行,是否会更快。

控制台。Writeline为你处理同步,所以它总是像在单个线程上运行一样。

从这里

:

…分别调用SetIn、SetOut或SetError方法。I/O使用这些流的操作是同步的,这意味着多个操作线程可以从流中读取或写入数据。

并行版本从在多个线程上运行中获得的任何优势都将通过控制台完成的封送处理而丢失。事实上,如果看到所有的线程切换实际上意味着并行运行将变慢,我不会感到惊讶。

尝试在动作中做其他事情(一个简单的线程)。如果可以由多个线程并发地处理,那么您应该可以看到在运行时间上的巨大差异。足够大,使用DateTime作为计时机制的不准确性不会造成太大影响。

这不是执行时间的问题。控制台的输出取决于如何安排操作的运行。为了获得准确的执行时间,您应该使用秒表。无论如何,您使用的是Console.Writeline,所以它看起来好像是在一个执行线程中。您试图通过使用parallel.invoke获得的任何东西都将因Console.Writeline的性质而丢失。

在这样简单的情况下,运行时间是相同的。什么平行。Invoke所做的是同时运行两个方法。

在第一种情况下,您将以混乱的顺序向控制台吐出行。

Method=BasicAction2, Thread=6, i=9776
Method=BasicAction, Thread=10, i=9985
// <snip>
Method=BasicAction, Thread=10, i=9999
Method=BasicAction2, Thread=6, i=9777

在第二种情况下,所有的BasicAction都在BasicAction2之前。

这显示的是两个方法同时运行

在理想情况下(如果委托的数量等于并行线程的数量&有足够的cpu内核)操作的持续时间将变成MAX(AllDurations)而不是SUM(AllDurations)(如果AllDurations是每个委托执行时间的列表,如{1sec,10sec, 20sec, 5sec})。在不太理想的情况下,它向这个方向移动。

当你不关心委托调用的顺序时,它很有用,但你关心你阻塞线程执行直到每个委托完成,所以它可能是一种情况,你需要从各种来源收集数据,然后才能继续(他们可以是web服务或其他类型的来源)。

Parallel.For可以更频繁地使用,我认为,在这种情况下,它几乎需要你得到不同的任务,每个任务都需要大量的持续时间来执行,我想如果你不知道可能的执行时间范围(这对web服务来说是真的),调用将最闪耀。

也许你的静态构造函数需要建立两个独立的字典供你的类型使用,你可以使用invoke()并行调用填充它们的方法,如果它们花费的时间大致相同,可以缩短时间2x。