-2

在我的应用程序中,我有一个与 PLC 通信的通信驱动程序,这工作正常。我想管理所有值更新请求,为此我创建了在 ValueListenManager 中注册自身的 ValueListener 对象,这也可以正常工作。在我的同步测试中,UI 性能正如预期的那样缓慢。现在完美了,让我们让它异步。

我尝试了不同的方法,如 backgroundworker、timer 和 Task.Run,​​这是迄今为止我能做的最好的方法,它可以工作,如果我 printscreen 任务 ManagedThreadId 线程 ID 不同(告诉我它应该是异步的)

但是 UI 响应性能似乎并没有真正提高,这告诉我它并不是真正的异步。谁能帮我这个?

到目前为止我发现的唯一奇怪的事情是 ValueListener 可以添加到 Managers ListenList 而 CheckPlcValuesTask 已经更新,这也表明它并不是真正的异步,我做错了什么?(我是异步编程的新手,因此感谢任何帮助或提示)

编辑:代码现在可以编译

  public class CommManager
     {
         public static class ValueListenManager
        {
            static private List<ValueListener> ListenList = new List<ValueListener>();

            public async static void Start()
            {                    
                var UpdateChangedValues = new Progress<List<ValueListener>>(UiUpdateList =>
                {
                    foreach (ValueListener item in UiUpdateList)
                        item.TriggerChange();
                });
                await Task.Run(() => CheckPlcValuesTask(UpdateChangedValues));
            }


            private static Task CheckPlcValuesTask(IProgress<List<ValueListener>> progressList)
            {
                List<ValueListener> returnList = new List<ValueListener>();
                while (true)
                {
                    if (returnList.Count != 0)
                        returnList.Clear();

                    Parallel.ForEach(ListenList, (CurrentItem) =>  // ListenList is the static List declared in the top
                    {
                        if (CurrentItem.CheckValue())
                            returnList.Add(CurrentItem);
                    });

                    if (progressList != null)
                    {
                        progressList.Report(returnList);
                        Thread.Sleep(1000);
                    }
                }

            }

            static internal void RegisterLister(ValueListener Listner)
            {
                ListenList.Add(Listner);
            }

            static internal void UnRegisterLister(ValueListener Listner)
            {
                ListenList.Remove(Listner);
            }
        }
    }
}


internal class ValueListener
{
    public event EventHandler<ValueChangeEventArgs> Changed;
    public string FullPath { get; }
    public object Value { get; private set; }
    private object oldObjectValue;

    internal ValueListener(string Path) // update prio is a enum
    {
        this.FullPath = Path;
        CommManager.ValueListenManager.RegisterLister(this);   // here i register into the ListenList above
    }

    ~ValueListener()
    {
        CommManager.ValueListenManager.UnRegisterLister(this);  // de-register after destruction
    }

    // Check for value changes
    public bool CheckValue()
    {
        var SmallTest = new Random();
        Value = SmallTest.Next(1, 5);
        if (Value != null && !Value.Equals(oldObjectValue))
            return true;

        return false;
    }


    // Check for value change, here is where i trigger updates on the UI
    public void TriggerChange()
    {
        if (Changed != null)
            Changed.Invoke(this, new ValueChangeEventArgs(Value, oldObjectValue));
        oldObjectValue = Value;
    }
}


public class ValueChangeEventArgs : EventArgs
{
    public ValueChangeEventArgs(object Value, object OldValue)
    { }
}
4

1 回答 1

0

这对你来说应该没问题。它利用了 Microsoft TPL Dataflow,它以 nuget 包的形式提供。

public static partial class CommManager
{
    public static class ValueListenManager
    {
        public static event Action<object> NewValueAvailable;

        private static Thread s_valueQueryThread;
        private static ActionBlock<object> s_newValueActionBlock;
        private static bool s_shouldRun;

        private static Random s_valueGenerator; //for testing purposes

        public static void Start()
        {
            //These flow options will make sure your action block executes on the UI thread. Make sure you call start on the UI Thread!
            var flowOptions = new ExecutionDataflowBlockOptions(){ TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext() };

            s_newValueActionBlock = new ActionBlock<object>(new Action<object>(OnNewValue), flowOptions);
            s_valueQueryThread = new Thread(CheckPlcValues);

            s_valueQueryThread.IsBackground = true;
            s_valueQueryThread.Start();
        }

        public static void Stop()
        {
            s_shouldRun = false;

            s_valueQueryThread.Join();
            s_valueQueryThread = null;

            s_newValueActionBlock.Complete();
            s_newValueActionBlock = null;
        }

        private static void OnNewValue(object value)
        {
            if(NewValueAvailable != null)
                NewValueAvailable(value);
        }

        private static void CheckPlcValues()
        {
            s_shouldRun = true;

            while(s_shouldRun)
            {
                var curPlcValue = s_valueGenerator.Next(1, 5);

                s_newValueActionBlock.Post(curPlcValue);

                Thread.Sleep(1000);
            }
        }
    }
}

internal class ValueListener
{
    public event EventHandler<ValueChangeEventArgs> ValueChanged;

    public string FullPath { get; private set; }
    public object Value { get; private set; }

    internal ValueListener(string path)
    {
        this.FullPath = path;
        CommManager.ValueListenManager.NewValueAvailable += CommManager_ValueListenManager_NewValueAvailable;
    }

    ~ValueListener()
    {
        CommManager.ValueListenManager.NewValueAvailable -= CommManager_ValueListenManager_NewValueAvailable;
    }

    void CommManager_ValueListenManager_NewValueAvailable(object newValue)
    {
        if(newValue != null && !newValue.Equals(Value))
        {
            var args = new ValueChangeEventArgs(newValue, Value);
            Value = newValue;

            if(ValueChanged != null)
                ValueChanged(this, args);
        }
    }
}

public class ValueChangeEventArgs : EventArgs
{
    public ValueChangeEventArgs(object Value, object OldValue) { }
}
于 2017-09-20T00:12:37.057 回答