开发者

When is Parallel.Invoke useful?

开发者 https://www.devze.com 2023-03-29 16:15 出处:网络
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

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.ToS开发者_如何学JAVAtring());
    Console.Read();
}

static void BasicAction()
{
    Thread.Sleep(100);

}

static void BasicAction2()
{
    Thread.Sleep(100);
}


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.


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.


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.


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消