Parallel.Invoke 什么时候有用?
我正在深入学习 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 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
你所做的测试毫无意义;您正在测试无法并行执行的某些操作,如果并行执行它是否会更快。
Console.Writeline 为您处理同步,因此它始终就像在单个线程上运行一样。
来自此处:
并行版本从在多个线程上运行中获得的任何优势都会因控制台完成的封送而丢失。事实上,如果我看到所有线程切换实际上意味着并行运行会变慢,我不会感到惊讶。
尝试在可以由多个线程同时处理的操作中执行其他操作(简单的 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:
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.
这不是执行时间的问题。控制台的输出取决于操作的运行计划方式。要获得准确的执行时间,您应该使用StopWatch。无论如何,您正在使用Console.Writeline,因此它看起来就像在一个执行线程中一样。您尝试使用parallel.invoke 实现的任何目标都会因Console.Writeline 的本质而丢失。
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 usingparallel.invoke
is lost by the nature ofConsole.Writeline
.对于这样简单的事情,运行时间将是相同的。 Parallel.Invoke 所做的是同时运行这两个方法。
在第一种情况下,您将以混合顺序将行吐出到控制台。
在第二种情况下,您将在 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.
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.
在理想情况下(如果委托数量等于并行线程数量并且有足够的 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 ofSUM(AllDurations)
(ifAllDurations
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.