开发者

.NET Bug - Threading.Timer affects Parallel.For performance

开发者 https://www.devze.com 2023-01-23 15:07 出处:网络
I have a VB.NET WinForms application开发者_StackOverflow中文版 which makes use of sequential Parallel.For statements.

I have a VB.NET WinForms application开发者_StackOverflow中文版 which makes use of sequential Parallel.For statements.

After adding a Threading.Timer, the Parallel.For loops slow to a crawl and the amount of kernel time jumps to nearly 80 percent.

The two are not related in my code (i.e. neither is run by the other), nor do they share any code or data.

Removing the timer fixes the problem.

Has anyone else experienced this behavior? What is the best method for working around this behaviour (would rather not create a WinForms Timer but will if I have to)?

This is the code executed by the Timer:

Public Sub Tick()
  IO.File.WriteAllText("c:\test.txt", DateTime.Now.ToString())
End Sub

This is the timer creation statement:

tmrFile = New Threading.Timer(AddressOf Tick, Nothing, New TimeSpan(0, 0, 0), New TimeSpan(0, 1, 0))


Is your timer signaling very often? If so, you might be getting overwhelmed in the number of threads being fired from the timer. There is a finite number of threads that can be running and if the Timer is taking too much time from signaling too often then the rest of your code is going to suffer.

Can you analyze what your timer is doing and share that information? How often it signals, any particularly rough code it's executing, if it is doing parallel tasks too, etc.


Try taking it out of the thread pool! I threw together a simple timer class for you to try out (not production code, mind you). This class runs in a separate thread.

The class:

  public class ThreadedTimer : IDisposable
  {
     private readonly AutoResetEvent _isStopping = new AutoResetEvent(false);
     public ThreadedTimer(Action f, int interval)
     {
        Thread t = new Thread(() =>
        {
           while (!_isStopping.WaitOne(interval))
           {
              f();
           }
        });
        t.IsBackground = true;
        t.Start();
     }

     public void Dispose()
     {
        _isStopping.Set();
     }
  }

Start a timer:

var timer = new ThreadedTimer(() => Debug.WriteLine("Test"), 1000);

Update: Completely untested code in VB below

Imports System.Threading
Public Class ThreadedTimer
    Implements IDisposable
    Private ReadOnly _isStopping As New AutoResetEvent(False)

    Public Sub New(ByVal f As Action, ByVal interval As Integer)
        Dim t As New Thread(Sub()
                                While Not _isStopping.WaitOne(interval)
                                    f()
                                End While
                            End Sub)
        t.IsBackground = True
        t.Start()
    End Sub

    Public Overloads Sub Dispose() Implements IDisposable.Dispose
        _isStopping.[Set]()
    End Sub
End Class
0

精彩评论

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