Parallel.Invoke 什么时候有用?

发布于 2024-11-30 22:56:33 字数 1827 浏览 5 评论 0原文

我正在深入学习 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 服务的异步调用更有用还是......?

编辑:我用Stopwatch删除了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);
}

I'm just diving into learning about the Parallel class in the 4.0 Framework and am trying to understand when it would be useful. At first after reviewing some of the documentation I tried to execute two loops, one using Parallel.Invoke and one sequentially like so:

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

There is no noticeable difference in time of execution here, or am I missing the point? Is it more useful for asynchronous invocations of web services or...?

EDIT: I removed the DateTime with Stopwatch, removed the write to the console with a simple addition operation.

UPDATE - Big Time Difference Now: Thanks for clearing up the problems I had when I involved 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);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

旧街凉风 2024-12-07 22:56:33

你所做的测试毫无意义;您正在测试无法并行执行的某些操作,如果并行执行它是否会更快。

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

来自此处

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

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

尝试在可以由多个线程同时处理的操作中执行其他操作(简单的 Thread.Sleep 即可),您应该会看到运行时间有很大差异。足够大,使用 DateTime 作为计时机制的不准确性不会太重要。

The test you are doing is nonsensical; you are testing to see if something that you can not perform in parallel is faster if you perform it in parallel.

Console.Writeline handles synchronization for you so it will always act as though it is running on a single thread.

From here:

...call the SetIn, SetOut, or SetError method, respectively. I/O
operations using these streams are synchronized, which means multiple
threads can read from, or write to, the streams.

Any advantage that the parallel version gains from running on multiple threads is lost through the marshaling done by the console. In fact I wouldn't be surprised to see that all the thread switching actually means that the parallel run would be slower.

Try doing something else in the actions (a simple Thread.Sleep would do) that can be processed by multiple threads concurrently and you should see a large difference in the run times. Large enough that the inaccuracy of using DateTime as your timing mechanism will not matter too much.

泪意 2024-12-07 22:56:33

It's not a matter of time of execution. The output to the console is determined by how the actions are scheduled to run. To get an accurate time of execution, you should be using StopWatch. At any rate, you are using Console.Writeline so it will appear as though it is in one thread of execution. Any thing you have tried to attain by using parallel.invoke is lost by the nature of Console.Writeline.

二货你真萌 2024-12-07 22:56:33

对于这样简单的事情,运行时间将是相同的。 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。

这表明这两个方法同时运行。

On something simple like that the run times will be the same. What Parallel.Invoke is doing is running the two methods at the same time.

In the first case you'll have lines spat out to the console in a mixed up order.

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

In the second case you'll have all the BasicAction's before the BasicAction2's.

What this shows you is that the two methods are running at the same time.

窗影残 2024-12-07 22:56:33

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

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

我认为 Parallel.For 可以更频繁地使用,在这种情况下,它几乎要求您获得不同的任务,并且每个任务都需要相当长的时间来执行,而且我想如果您没有可能的执行时间范围的想法(这对于 Web 服务来说是正确的)Invoke 将最引人注目。

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

In ideal case (if number of delegates is equal to number of parallel threads & there are enough cpu cores) duration of operations will become MAX(AllDurations) instead of SUM(AllDurations) (if AllDurations is a list of each delegate execution times like {1sec,10sec, 20sec, 5sec} ). In less idealcase its moving in this direction.

Its useful when you don't care about the order in which delegates are invoked, but you care that you block thread execution until every delegate is completed, so yes it can be a situation where you need to gather data from various sources before you can proceed (they can be webservices or other types of sources).

Parallel.For can be used much more often I think, in this case its pretty much required that you got different tasks and each is taking substantial duration to execute, and I guess if you don't have an idea of possible range of execution times ( which is true for webservices) Invoke will shine the most.

Maybe your static constructor requires to build up two independant dictionaries for your type to use, you can invoke methods that fill them using Invoke() in parallel and shorten time 2x if they both take roughly same time for example.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文