Blog Archive

Wednesday, July 25, 2012

High Performance WPF/WCF


Serveral Keys for High Performance:
(1) WPF need to use ThreadPool (Task/ParallelFor) to call WCP in the backgroud
(2) Return data should be on Queues for Dispatcher Timer to pick up and update UI
(3) WCF Instancing.Single and Concurrency.Multiple seems to have better network 
through-put than Single/Single 
( Total B/Sec in Win8 Resource Monitor 220 vs 280, 20%+). But this not a serious performance Testing)
(4) one thing for sure: when Task is removed, UI will be slugish.





   public delegate void OnHeartbeat();
  
    public partial class MainWindow : Window
    {
        const int NUM = 5000;
        public event OnHeartbeat Heartbeat;
        DispatcherTimer t;
        DispatcherTimer t2;
        List<RealtimeData> dataList = new List<RealtimeData>();
        Dictionary<int, Queue> qList = new Dictionary<int, Queue<string>>();

        public MainWindow()
        {
            InitializeComponent();
            t = new DispatcherTimer() { Interval = new TimeSpan(0, 0, 0, 0, 1) };
            t.Tick += new EventHandler(t_Tick);
            t2 = new DispatcherTimer() { Interval = new TimeSpan(0, 0, 0, 0, 1) };
            t2.Tick += new EventHandler(t_Tick2);
            AddGridCell();
            t.Start();
            t2.Start();
        }

        void t_Tick(object sender, EventArgs e)
        {
            if (Heartbeat != null) Heartbeat();
        }

        void t_Tick2(object sender, EventArgs e)
        {
   
            Task.Factory.StartNew(() =>
            {
                Parallel.For(0, NUM, (ii) =>
               // for (int ii = 0; ii < NUM; ii++)
                {
                    try
                    {
                        ServiceReference1.Service1Client c = new ServiceReference1.Service1Client();
                        qList[ii].Enqueue(c.GetData(ii));
                        c.Close();
                    }
                    catch (Exception ex)
                    {
                        EventLog.WriteEntry("Application", ex.Message + " " + ex.StackTrace);
                    }
                });
               // }
            });
        }

        void AddGridCell()
        {

            for (int i = 0; i < NUM; i++)
            {
                qList.Add(i, new Queue());
                RealtimeData rtD = MakeDataItem(i);
                this.Heartbeat += rtD.UpdateData;
                dataList.Add(rtD);
                wrapPanel1.Children.Add(rtD);
            }
        }

  
        RealtimeData MakeDataItem(int i)
        {
            return new RealtimeData(qList[i]) { Width = 50, Height = 50, BorderBrush = new SolidColorBrush(Colors.Black), BorderThickness = new Thickness(2) };
        }

      
    
    }

    public class RealtimeData : UserControl
    {
        Label lb = new Label();
        Queue<string> _q; 
        public RealtimeData(Queue<string> q)
        {
            _q = q;
            this.AddChild(lb);
        }

        public void UpdateData()
        {
            int i = _q.Count;
            if (_q.Count > 0) lb.Content =i.ToString()+" "+ _q.Dequeue();
        }
 
    }




  // [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode=ConcurrencyMode.Multiple)]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)]
    public class Service1 : IService1
    {
      
        public string GetData(int value)
        {
          //  Thread.SpinWait(300000);
            Random r = new Random();
            return string.Format(r.NextDouble().ToString());
        }

    }

No comments: