user3704628
user3704628

Reputation: 305

C# Task.Run slowing my wpf program

Short story: I am designing software to validate some things in a CAD application. When I try parallelism it gets very slow in WPF only.

Long story: I have my software that asks questions of my library (.dll) that I also made and that library communicates with my CAD software(E3.series from Zuken).

My software was originally made in WinForms and everything was good but the interface I thought would really benefit from WPF because of the binding. So I went and translated that, but found it's way slower. So I did 2 mini projects to find where it was getting a lot slower. Here are the results and I can't find why:

This code is just as fast as Winforms (3.5 sec) :

private void Grid_Loaded(object sender, RoutedEventArgs e)
{
    Stopwatch timer = new Stopwatch();
    timer.Start();
    List<Wire> wires = e3.Project.Wires;
    timer.Stop();
    MessageBox.Show("WPF " + wires.Count + " in " + timer.Elapsed);
}

But when I do this it's (12 sec) :

private void Grid_Loaded(object sender, RoutedEventArgs e)
{
    Task.Run(() =>
        {
            Stopwatch timer = new Stopwatch();
            timer.Start();
            List<Wire> wires = e3.Project.Wires;
            timer.Stop();
            MessageBox.Show("WPF " + wires.Count + " in " + timer.Elapsed);
        });
}

It's exactly the same with a BackgroundWorker.

I need to use Task.Run and Parallel.ForEach because I have a lot of long tasks to parallelize. My WinForms application got 5-6 times faster when I changed to Parallel.ForEach so I don't want to lose that gain for switching to WPF.

I see my CPU is running higher with the empty WPF window so it might be that there isn't enough CPU for my CAD application to work and answer my dll?

What I think I discovered with CPU usage analyser in VS2015 is that it's really the COM call from my library to my CAD software that are a lot slower because of my app.

Upvotes: 5

Views: 1620

Answers (2)

TnTinMn
TnTinMn

Reputation: 11801

Both a WinForm and WPF application UI runs in a Static Thread Apartment(STA) model. You mention that using either Task.Run or Background worker degrades performance. Since both of these create Multi-Threaded Apartment (MTA) threads, the issue may be due marshaling if the COM component is created in a STA. See the "Mixed Model Development" section of Understanding and Using COM Threading Models for more information.

You could try creating a STA thread and run your code on that.

Thread t = new Thread(ThreadWorkMethod);
t.SetApartmentState(ApartmentState.STA);
t.Start();

Upvotes: 2

Phil Wright
Phil Wright

Reputation: 22906

First of all you should not be called MessageBox.Show inside the thread pool because they are not setup as user interface threads.

Second, make sure the e3.Project.Wires property does not perform any user interface actions either.

Third, try using the following method to queue work for the thread pool...

ThreadPool.QueueUserWorkItem(ThreadProc, e3);

...implementing the method like this...

static void ThreadProc(Object stateInfo) 
{
    ??? e3 = (???)stateInfo;
    Stopwatch timer = new Stopwatch();
    timer.Start();
    List<Wire> wires = e3.Project.Wires;
    timer.Stop();
    Console.WriteLine("WPF " + wires.Count + " in " + timer.Elapsed);
}

Obviously you would need to cast the incoming parameter to the correct type.

Upvotes: 0

Related Questions