2015年11月23日 星期一

[參考程式碼][WebService]最佳化呼叫WebService的頻率(Winform版本)

Form的外觀:

Form1.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;

namespace TPEPublicValuePriceWinForm
{
    public partial class Form1 : Form
    {
        //臺北市的timer
        System.Windows.Forms.Timer tpeProgrssBarTimer = new System.Windows.Forms.Timer();
        System.Windows.Forms.Timer tpeQueryTPETimer = new System.Windows.Forms.Timer();
        System.Windows.Forms.Timer tpeAvgSpeedTimer = new System.Windows.Forms.Timer();
        

        //新北市的timer
        System.Windows.Forms.Timer newTpeProgrssBarTimer = new System.Windows.Forms.Timer();
        System.Windows.Forms.Timer newTpeQueryTPETimer = new System.Windows.Forms.Timer();
        System.Windows.Forms.Timer newTpeAvgSpeedTimer = new System.Windows.Forms.Timer();
        

        bool tpeWCFCalling = false;
        bool newTpeWCFCalling = false;


        //臺北市的狀態記錄
        int tpeNowCount;//現在執行完畢的筆數
        int tpeOldCount;//五秒前的執行完畢的筆數   
        int tpeTotalCount;//臺北市總筆數

        //新北市的狀態記錄
        int newTpeNowCount;//現在執行完畢的筆數
        int newTpeOldCount;//五秒前的執行完畢的筆數   
        int newTpeTotalCount;//新北市總筆數

        //臺北市的平均執行速度狀態記錄
        int tpeOldMinuteCount; //一分鐘前執行完畢的筆數
        int tpeNowMinuteCount; //目前執行完畢的筆數        

        //新北市的平均執行速度狀態記錄
        int newTpeOldMinuteCount; //一分鐘前執行完畢的筆數
        int newTpeNowMinuteCount; //目前執行完畢的筆數

        string tpeCityCode = "0000"; //臺北市城市代碼        
        string newTpeCityCode = "0001";//新北市程式代碼



        public Form1()
        {

            InitializeComponent();
            init();

        }

        private void init()
        {
            //初始化筆數
            using (rehouseEntities db = new rehouseEntities())
            {
                //臺北市總筆數
                TPETotalCountLbl.Text = db.pft23.Where(p => p.city_code == tpeCityCode).Count().ToString();
                tpeTotalCount = Convert.ToInt32(TPETotalCountLbl.Text);
                //臺北市執行完畢筆數                
                TPEFinCountLbl.Text = GetTpeFinCountNow().ToString();

                //新北市總筆數
                NewTPETotalCountLbl.Text = db.pft23.Where(p => p.city_code == newTpeCityCode).Count().ToString();
                newTpeTotalCount = Convert.ToInt32(NewTPETotalCountLbl.Text);
                //新北市執行完畢筆數                
                NewTPEFinCountLbl.Text = GetNewTpeFinCountNow().ToString();

            }

            //為timer設定事件
            //臺北市
            tpeProgrssBarTimer.Interval = Convert.ToInt16(Config.ProgressBarCheckTime);//3 secs顯示一次進度
            tpeProgrssBarTimer.Tick += new System.EventHandler(tpeProgrssBarTimer_Tick);
            tpeQueryTPETimer.Interval = Convert.ToInt16(Config.SleepTime);//10 secs檢查一次是否有正在查詢
            tpeQueryTPETimer.Tick += new System.EventHandler(tpeQueryTPETimer_Tick);
            tpeAvgSpeedTimer.Interval = Convert.ToInt32(Config.AverageSpeedCheckTime);//60 secs檢查一次是否有正在查詢
            tpeAvgSpeedTimer.Tick += new System.EventHandler(queryTPEAverageSpeed_Tick);
            
            //新北市
            newTpeProgrssBarTimer.Interval = Convert.ToInt16(Config.ProgressBarCheckTime);//3 secs顯示一次進度
            newTpeProgrssBarTimer.Tick += new System.EventHandler(newTpeProgrssBarTimer_Tick);
            newTpeQueryTPETimer.Interval = Convert.ToInt16(Config.SleepTime);//10 secs檢查一次是否有正在查詢
            newTpeQueryTPETimer.Tick += new System.EventHandler(newTpeQueryTPETimer_Tick);
            newTpeAvgSpeedTimer.Interval = Convert.ToInt32(Config.AverageSpeedCheckTime);//60 secs檢查一次是否有正在查詢
            newTpeAvgSpeedTimer.Tick += new System.EventHandler(queryNewTPEAverageSpeed_Tick);
            
        }

        #region control event

        //按下查詢臺北
        private void QueryTPEBtn_Click(object sender, EventArgs e)
        {            
            TPETimerStart();            
            exeTPEStatusLbl.Text = "執行中";            
            exeTPEStatusLbl.Text = "執行中";
            tpeNowCount = GetTpeFinCountNow();
            tpeOldCount = tpeNowCount;
            tpeNowMinuteCount = tpeNowCount;                                          
            tpeOldMinuteCount = tpeNowCount;
            MessageBox.Show("已開始查詢臺北!");
        }

        //停止查詢臺北
        private void stopTPEBtn_Click(object sender, EventArgs e)
        {
            tpeProgrssBarTimer.Stop();
            tpeQueryTPETimer.Stop();
            tpeAvgSpeedTimer.Stop();
            exeTPEStatusLbl.Text = "停止";
            MessageBox.Show("已停止查詢臺北!");
        }

        //按下查詢新北
        private void QueryNewTPEBtn_Click(object sender, EventArgs e)
        {            
     
            NewTPETimerStart();
            exeNewTPEStatusLbl.Text = "執行中";                        

            exeNewTPEStatusLbl.Text = "執行中";
            newTpeNowCount = GetNewTpeFinCountNow();
            newTpeOldCount = newTpeNowCount;
            newTpeNowMinuteCount = newTpeNowCount;                                           
            newTpeOldMinuteCount = newTpeNowCount;
            MessageBox.Show("已開始查詢新北!");
        }

        //停止查詢新北
        private void stopNewTPEBtn_Click(object sender, EventArgs e)
        {
            newTpeProgrssBarTimer.Stop();
            newTpeQueryTPETimer.Stop();
            newTpeAvgSpeedTimer.Stop();
            exeNewTPEStatusLbl.Text = "停止";
            MessageBox.Show("已停止查詢新北!");
        }


        #endregion

        #region Timer Event
        //持續更新畫面上查詢臺北的進度
        private void tpeProgrssBarTimer_Tick(object sender, EventArgs e)
        {

            TPEFinCountLbl.Text = GetTpeFinCountNow().ToString();
            int temp = DateTime.Now.Millisecond % 3;
            if(temp ==0)
            {
                exeTPEStatusLbl.Text = "執行中。。。。。。";
            }
            else if (temp == 1)
            {
                exeTPEStatusLbl.Text = "執行中。。。。";
            }
            else if (temp == 2)
            {
                exeTPEStatusLbl.Text = "執行中。。";
            }
            
        }

        //每3秒持續呼叫臺北wcf一次
        private void tpeQueryTPETimer_Tick(object sender, EventArgs e)
        {
            
            tpeNowCount = GetTpeFinCountNow();//現在執行完畢的筆數
            //尚未達到總筆數的時候
            if (tpeNowCount != tpeTotalCount)
            {
                //等上次呼叫的兩百筆執行完才繼續呼叫

                if (tpeNowCount == tpeOldCount
                    || tpeNowCount >= tpeOldCount + Convert.ToInt32(Config.OnceTakeCount)
                    - Convert.ToInt32(Config.OnceTakeCount) * Convert.ToDouble(Config.NoResponseRate))
                {
                    //上次呼叫的執行完的時候,接續著呼叫下一個兩百筆wcf
                    //或是只差一點就執行完畢兩百筆的時候,接著呼叫下一個兩百筆
                    //呼叫之前,先記錄目前執行完畢的筆數
                    //如果正在呼叫中,就不要一直呼叫,不然iis會過載
                    if (tpeWCFCalling == false)
                    {
                        tpeOldCount = GetTpeFinCountNow();
                        tpeWCFCalling = true;
                        Task.Run(() => QueryTPEByService());
                    }
                }
                else if(tpeNowCount < tpeOldCount + Convert.ToInt32(Config.OnceTakeCount))
                {
                    //還沒執行完上次呼叫的兩百筆,什麼都不做
                }
                else
                {
                    //
                    
                }

            }
            else
            {
                //已經到達總筆數
                TPEFinCountLbl.Text = tpeNowCount.ToString();
                exeTPEStatusLbl.Text = "已執行完畢!";
                StopTpeTimer();
            }

            
        }

        //確認每分鐘臺北查詢速度
        private void queryTPEAverageSpeed_Tick(object sender, EventArgs e)
        {
            using (rehouseEntities db = new rehouseEntities())
            {
                tpeNowMinuteCount = GetTpeFinCountNow();
                string avgSpeedResult = DateTime.Now.ToString("hh:mm") + "完成筆數:" + Convert.ToString(tpeNowMinuteCount - tpeOldMinuteCount);
                TPEAvgSpeedTxt.Text = TPEAvgSpeedTxt.Text + avgSpeedResult + "\r\n";
                //每三分鐘檢查一次是否速度降為零
                //是的話,就重送
                if (DateTime.Now.Minute % 3 == 0 && tpeNowCount != tpeTotalCount)
                {
                    if (tpeNowMinuteCount - tpeOldMinuteCount == 0)
                    {
                        tpeOldCount = tpeNowCount;
                    }
                }
         
                tpeOldMinuteCount = GetTpeFinCountNow();//記錄一分鐘前執行完畢的筆數
            }
        }

       

        //持續更新畫面上查詢新北的進度
        private void newTpeProgrssBarTimer_Tick(object sender, EventArgs e)
        {

            NewTPEFinCountLbl.Text = GetNewTpeFinCountNow().ToString();
            int temp = DateTime.Now.Millisecond % 3;
            if (temp == 0)
            {
                exeNewTPEStatusLbl.Text = "執行中。。";
            }
            else if (temp == 1)
            {
                exeNewTPEStatusLbl.Text = "執行中。。。。。。";
            }
            else if (temp == 2)
            {
                exeNewTPEStatusLbl.Text = "執行中。。。。";
            }
            
        }

        //每五秒持續呼叫新北wcf一次
        private void newTpeQueryTPETimer_Tick(object sender, EventArgs e)
        {
           

            newTpeNowCount = GetNewTpeFinCountNow();//現在執行完畢的筆數
            //尚未達到總筆數的時候
            if (newTpeNowCount != newTpeTotalCount)
            {
                //等上次呼叫的兩百筆執行完才繼續呼叫
                if (newTpeNowCount == newTpeOldCount
                    || newTpeNowCount >= newTpeOldCount + Convert.ToInt32(Config.OnceTakeCount)
                    - Convert.ToInt32(Config.OnceTakeCount) * Convert.ToDouble(Config.NoResponseRate))
                {
                    //上次呼叫的執行完的時候,接續著呼叫下一個兩百筆wcf
                    //或是只差一點就執行完畢兩百筆的時候,接著呼叫下一個兩百筆
                    //呼叫之前,先記錄目前執行完畢的筆數
                    //如果正在呼叫中,就不要一直呼叫,不然iis會過載
                    if (newTpeWCFCalling == false)
                    {
                        newTpeOldCount = GetNewTpeFinCountNow();
                        newTpeWCFCalling = true;
                        Task.Run(() => QueryNewTPEByService());
                    }
                }
                else if (newTpeNowCount < newTpeOldCount + Convert.ToInt32(Config.OnceTakeCount))
                {
                    //還沒執行完上次呼叫的兩百筆,什麼都不做
                }
                else
                {
                    //

                }

            }
            else
            {
                //已經到達總筆數
                NewTPEFinCountLbl.Text = newTpeNowCount.ToString();
                exeNewTPEStatusLbl.Text = "已執行完畢!";
                StopNewTpeTimer();
            }


        }

        //確認每分鐘新北查詢速度
        private void queryNewTPEAverageSpeed_Tick(object sender, EventArgs e)
        {
            using (rehouseEntities db = new rehouseEntities())
            {
                newTpeNowMinuteCount = GetNewTpeFinCountNow();
                string avgSpeedResult = DateTime.Now.ToString("hh:mm") + "完成筆數:" + Convert.ToString(newTpeNowMinuteCount - newTpeOldMinuteCount);
                NewTPEAvgSpeedTxt.Text = NewTPEAvgSpeedTxt.Text + avgSpeedResult + "\r\n";
                //每三分鐘檢查一次是否速度降為零
                //是的話,就重送
                if (DateTime.Now.Minute % 3 == 0 && newTpeNowCount != newTpeTotalCount)
                {
                    //如果新北市官網的回應太少導致ResponseRate太低導致該分鐘的速度為0的話,就再度重送
                    if (newTpeNowMinuteCount - newTpeOldMinuteCount == 0)
                    {
                        newTpeOldCount = newTpeNowCount;
                    }
                }
                

                newTpeOldMinuteCount = GetNewTpeFinCountNow();//記錄一分鐘前執行完畢的筆數
            }
        }

        private void StopTpeTimer()
        {
            tpeProgrssBarTimer.Stop();
            tpeQueryTPETimer.Stop();
            tpeAvgSpeedTimer.Stop();
     
        }

        private void StopNewTpeTimer()
        {
            newTpeProgrssBarTimer.Stop();
            newTpeQueryTPETimer.Stop();
            newTpeAvgSpeedTimer.Stop();
           
        }


        #endregion

        #region custom method

        //取得臺北目前查詢完畢的資料筆數
        private int GetTpeFinCountNow()
        {
            using (rehouseEntities db = new rehouseEntities())
            {
                return db.pft23.Where(p => (p.devo_value != null || p.ground_price != null) && p.city_code == tpeCityCode).Count();
            }
        }

        //呼叫wcf查詢臺北
        private void QueryTPEByService()
        {

            TPELandPublicValuePriceService.ServiceClient sc = new TPELandPublicValuePriceService.ServiceClient();
            using (rehouseEntities db = new rehouseEntities())
            {
                var pft23s = db.pft23.Where(p => p.devo_value == null && p.ground_price == null && p.city_code == tpeCityCode).Take(Convert.ToInt16(Config.OnceTakeCount));
                foreach (var p23 in pft23s)
                {
                    sc.GetTPELandPublicValuePrice(p23.zip_code, p23.session_id, p23.area_no);
                }

            }
            sc.Close();
            tpeWCFCalling = false;//呼叫完畢
        }

        //啟動臺北timer
        private void TPETimerStart()
        {
            tpeProgrssBarTimer.Start();
            tpeQueryTPETimer.Start();
            tpeAvgSpeedTimer.Start();
    
        }

        //取得新北目前查詢完畢的資料筆數
        private int GetNewTpeFinCountNow()
        {
            using (rehouseEntities db = new rehouseEntities())
            {
                return db.pft23.Where(p => (p.devo_value != null || p.ground_price != null) && p.city_code == newTpeCityCode).Count();
            }
        }

        //呼叫wcf查詢臺北
        private void QueryNewTPEByService()
        {
            TPELandPublicValuePriceService.ServiceClient sc = new TPELandPublicValuePriceService.ServiceClient();
            using (rehouseEntities db = new rehouseEntities())
            {
                var pft23s = db.pft23.Where(p => p.devo_value == null && p.ground_price == null && p.city_code == newTpeCityCode).Take(Convert.ToInt16(Config.OnceTakeCount));
                foreach (var p23 in pft23s)
                {
                    sc.GetNewTPELandPublicValuePrice(p23.zip_code, p23.session_id, p23.area_no);
                }

            }
            sc.Close();
            newTpeWCFCalling = false;//呼叫完畢
        }

        //啟動新北timer
        private void NewTPETimerStart()
        {
            newTpeProgrssBarTimer.Start();
            newTpeQueryTPETimer.Start();
            newTpeAvgSpeedTimer.Start();
        
        }
        #endregion


    }
}

Config.cs:方便快速存取appsetting用的類別
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;

namespace TPEPublicValuePriceWinForm
{
    public class Config
    {        
        public static string SleepTime = GetAppSettings("SleepTime");
        public static string ProgressBarCheckTime = GetAppSettings("ProgressBarCheckTime");
        public static string AverageSpeedCheckTime = GetAppSettings("AverageSpeedCheckTime");
        public static string ResponseLostTime = GetAppSettings("ResponseLostTime");
        
        public static string AutoStopCount = GetAppSettings("AutoStopCount");
        public static string AutoInitCount = GetAppSettings("AutoInitCount");
        public static string OnceTakeCount = GetAppSettings("OnceTakeCount");
        public static string NoResponseRate = GetAppSettings("NoResponseRate");

        private static string GetAppSettings(string key)
        {
            return  ConfigurationManager.AppSettings[key];
        }
    }
}


app.config檔裡面參考的參數:主要是設定timer每多少秒數要執行一次
<appSettings>  
<add key="SleepTime" value="3000"/>
<add key="ProgressBarCheckTime" value="3000"/>
<add key="AverageSpeedCheckTime" value="60000"/>
<add key="ResponseLostTime" value="150000"/>
<add key="AutoStopCount" value="10"/>
<add key="AutoInitCount" value="30"/>
<add key="OnceTakeCount" value="200"/>
<add key="NoResponseRate" value="0.1"/>

</appSettings>

沒有留言:

張貼留言