Parallel.Invoke什么时候有用?

问题描述 投票:2回答:4

我只是要深入学习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:我用秒表删除了DateTime,并通过简单的加法操作删除了对控制台的写入。

更新-时差大了:感谢您解决涉及控制台时遇到的问题

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);
}
c# c#-4.0 .net-4.0 parallel-processing
4个回答
6
投票

您正在进行的测试是荒谬的;您正在测试,看看是否可以并行执行某些无法更快执行的操作。

Console.Writeline为您处理同步,因此它将始终像在单个线程上运行一样。

来自here

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

通过在多个线程上运行而获得的并行版本所带来的任何好处都将通过控制台进行的封送处理而丢失。实际上,看到所有线程切换实际上意味着并行运行为slower

,我不会感到惊讶。

尝试在动作中做其他事情(一个简单的Thread.Sleep会做),可以由多个线程同时处理,并且您应该看到运行时间有很大的不同。足够大,以至于使用DateTime作为计时机制的准确性都不会太大。


2
投票

这与执行时间无关。控制台的输出取决于操作安排的运行方式。为了获得准确的执行时间,您应该使用StopWatch。无论如何,您都在使用Console.Writeline,因此它看起来像是在一个执行线程中。您尝试使用parallel.invoke获得的任何内容都会因Console.Writeline的性质而丢失。


1
投票

在诸如此类的简单操作上,运行时间将相同。 Parallel.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

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

这显示两个方法同时运行。


0
投票

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

当您不关心调用委托的顺序时非常有用,但是您关心的是阻塞线程执行直到每个委托完成,所以是的,在某些情况下,您需要先从各种来源收集数据您可以继续(它们可以是Web服务或其他类型的源)。

Parallel.For可以更频繁地使用,在这种情况下,它非常需要您执行不同的任务,并且每个任务都需要花费大量的时间来执行,我想您是否不知道可能的范围?执行时间(对于Web服务而言是正确的),调用将发光最多。

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

© www.soinside.com 2019 - 2024. All rights reserved.