2011-10-30 40 views
1

我有一個線程返回站點的http響應狀態,但有時我的程序返回錯誤結果。過了一段時間,它會給出好的結果。
假結果: 它需要一個大的安裝的時間來檢查,然後它說,(例如)谷歌是下降,這是很不合理的,但幾秒鐘後返回了良好的效果C#false http響應

你可以看看,並告訴我什麼是錯的?或我該如何改進它?
檢查DataGrid中的所有站點:

private void CheckSites() 
     { 
      if (CheckSelected()) 
      { 
       int rowCount = dataGrid.BindingContext[dataGrid.DataSource, dataGrid.DataMember].Count; 
       string url; 
       for (int i = 0; i < rowCount; i++) 
       { 
        url = dataGrid.Rows[i].Cells[2].Value.ToString(); 
        if (url != null) 
        { 
         Task<string[]> task = Task.Factory.StartNew<string[]> 
         (() => checkSite(url)); 

         // We can do other work here and it will execute in parallel: 
         //Loading... 

         // When we need the task's return value, we query its Result property: 
         // If it's still executing, the current thread will now block (wait) 
         // until the task finishes: 
         string[] result = task.Result; 
         selectRows(); 
         if (result[0] != System.Net.HttpStatusCode.OK.ToString() && result[0] != System.Net.HttpStatusCode.Found.ToString() && result[0] != System.Net.HttpStatusCode.MovedPermanently.ToString()) 
         { 
          //bad 
          notifyIcon1.ShowBalloonTip(5000, "Site Down", dataGrid.Rows[i].Cells[2].Value.ToString() + ", has a status code of:" + result, ToolTipIcon.Error); 
          dataGrid.Rows[i].DefaultCellStyle.BackColor = System.Drawing.Color.Wheat; 
          TimeSpan ts; 
          TimeSpan timeTaken = TimeSpan.Parse(result[1]); 
          dataGrid.Rows[i].Cells[3].Value = result[0]; 
          dataGrid.Rows[i].Cells[3].Style.BackColor = System.Drawing.Color.Red; 
          dataGrid.Rows[i].Cells[4].Value = timeTaken.Seconds.ToString() + "." + String.Format("{0:0.00000}", timeTaken.Milliseconds.ToString()) + " seconds."; 
          string sec = (DateTime.Now.Second < 10) ? "0" + DateTime.Now.Second.ToString() : DateTime.Now.Second.ToString(); 
          string min = (DateTime.Now.Minute < 10) ? "0" + DateTime.Now.Minute.ToString() : DateTime.Now.Minute.ToString(); 
          string hour = (DateTime.Now.Hour < 10) ? "0" + DateTime.Now.Hour.ToString() : DateTime.Now.Hour.ToString(); 
          dataGrid.Rows[i].Cells[5].Value = hour + ":" + min + ":" + sec; 

          //loadbar 
         } 
         else if (result[0] == "catch")//catch 
         { 
          notifyIcon1.ShowBalloonTip(10000, "SITE DOWN", dataGrid.Rows[i].Cells[1].Value.ToString() + ", Error:" +result[1], ToolTipIcon.Error); 
          dataGrid.Rows[i].Cells[3].Value = result[1]; 
          dataGrid.Rows[i].Cells[3].Style.BackColor = System.Drawing.Color.Red; 
          //loadbar 

         } 
         else 
         { 
          //good 
          TimeSpan timeTaken = TimeSpan.Parse(result[1]); 
          dataGrid.Rows[i].Cells[3].Value = result[0]; 
          dataGrid.Rows[i].Cells[3].Style.BackColor = System.Drawing.Color.LightGreen; 
          dataGrid.Rows[i].Cells[4].Value = timeTaken.Seconds.ToString() + "." + String.Format("{0:0.00000}", timeTaken.Milliseconds.ToString()) + " seconds."; 
          string sec = (DateTime.Now.Second < 10) ? "0" + DateTime.Now.Second.ToString() : DateTime.Now.Second.ToString(); 
          string min = (DateTime.Now.Minute < 10) ? "0" + DateTime.Now.Minute.ToString() : DateTime.Now.Minute.ToString(); 
          string hour = (DateTime.Now.Hour < 10) ? "0" + DateTime.Now.Hour.ToString() : DateTime.Now.Hour.ToString(); 
          dataGrid.Rows[i].Cells[5].Value = hour + ":" + min + ":" + sec; 
          //loadbar 
         } 
         selectRows(); 
        } 
       } 
      } 
     } 

檢查站點:

///////////////////////////////// 
     ////Check datagrid websites-button - returns response 
     ///////////////////////////////// 
     private string[] checkSite(string url) 
     { 
      string[] response = new string[2]; 
      url = dataGrid.Rows[0].Cells[2].Value.ToString(); 
      if (url != null) 
      { 
       try 
       { 
        HttpWebRequest httpReq; 


        httpReq.Timeout = 10000; 
        //loadbar 
        dataGrid.Rows[0].DefaultCellStyle.BackColor = System.Drawing.Color.Wheat; 
        System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch(); 
        timer.Start(); 
        HttpWebResponse httpRes = (HttpWebResponse)httpReq.GetResponse(); //httpRes.Close(); 
        timer.Stop(); 
        //loadbar 
        HttpStatusCode httpStatus = httpRes.StatusCode; 
        response[0] = httpStatus.ToString(); 
        response[1] = timer.Elapsed.ToString();//* 
        httpRes.Close(); 
        return response; 
       } 
       catch (Exception he) 
       { 
        response[0] = "catch"; 
        response[1] = he.Message; 
        return response; 
       } 
      } 
      response[0] = "catch"; 
      response[1] = "No URL entered"; 
      return response; 
      //dataGrid.Rows[i].DefaultCellStyle.BackColor = System.Drawing.Color.Blue; 

     } 

在此先感謝。

+2

請詳細解釋「虛假結果」和「好結果」的含義。 – Oded

+0

有多少網站正在並行檢查? – Yahia

+0

這是否發生在整個計算機中?例如,如果您一次使用您的網絡瀏覽器轉到Google,它會再次失敗嗎? –

回答

1

假設提供的代碼被用於實際的代碼:

首先,你的「假結果」和「好結果」的定義是錯誤的。如果你期望A但得到B,那並不意味着B是無效的。如果你的妻子正在分娩,你希望有一個男孩,但結果是一個女孩,這不是一個錯誤的結果。意想不到的。

這就是說:讓我們來分析一下你的工作:如果花了很長時間去檢查一個網站才終於得到一個???結果這不是200響應代碼。我們幾乎可以保守地認爲你正在處理超時。如果您的路由器,谷歌或其中任何基礎網絡設備出現問題,其預期會得到意想不到的答案。 「超時」,「錯誤的請求」,「服務器不可用」等。爲什麼會發生這種情況?如果沒有直接訪問您的環境,它是不可能說的。但是看看你的代碼,我發現你使用了默認的TaskScheduler來讓每次檢查作爲後臺任務運行(假設你沒有改變默認的任務調度器, )。默認任務調度程序調度線程池上的每個任務,這導致很多許多任務運行同步。這裏我們有一個很好的候選人來重載你的網絡。許多網站(尤其是谷歌)對於處理來自同一來源的許多請求(特別是如果頻率很高)時相當敏感,所以也許谷歌暫時阻止你或阻止你回來。同樣,在這一點上,它是純粹的推測,但事實上,你同時運行所有檢查(除非線程池在他的最大值)很可能是你的問題的原因。

UPDATE

我會建議用LimitedConcurrencyTaskScheduler工作(見這裏:http://blogs.msdn.com/b/pfxteam/archive/2010/04/09/9990424.aspx)。在這裏,您可以限制異步運行的任務數量。你必須做一些測試,以確定在你的情況下理想的數字。還要確保頻率不是太「太高」。很難定義什麼太高,只有測試才能證明這一點。

+0

是的,我認爲Google是問題所在,如果我可以補充一點,那麼在檢查時,爲了解凍程序,您會推薦做些什麼? – funerr

+0

@ agam360 - 我更新了我的答案。這對你有幫助嗎? – Polity

+0

最後,你認爲我的代碼可能返回不正確的響應時間嗎? – funerr

0

爲了模擬您的場景,我創建了一個帶有數據網格和按鈕的Winform。在窗體加載時,我以編程方式創建url列表(在表中)並綁定到數據網格。然後點擊按鈕,我們開始下載過程。簡而言之,你必須編寫更多的防禦性代碼,下面的代碼只是解決問題的一個框架。

using System; 
using System.Data; 
using System.Net; 
using System.Threading.Tasks; 
using System.Windows.Forms; 

namespace app 
{ 
    public partial class Form1 : Form 
    { 
     DataTable urls = new DataTable(); 
     public Form1() 
     { 
      InitializeComponent(); 
     } 
     //Fill your uri's and bind to a data grid. 
     void InitTable() 
     { 
      //Silly logic to simulate your scenario. 
      urls = new DataTable(); 
      urls.Columns.Add(new DataColumn("Srl", typeof(string))); 
      urls.Columns.Add(new DataColumn("Urls", typeof(Uri))); 
      urls.Columns.Add(new DataColumn("Result", typeof(string))); 

      DataRow dr = urls.NewRow(); 
      dr["Srl"] = "1"; 
      dr["Urls"] = new Uri("http://www.microsoft.com"); 
      dr["Result"] = string.Empty; 
      urls.Rows.Add(dr); 
      dr = urls.NewRow(); 
      dr["Srl"] = "2"; 
      dr["Urls"] = new Uri("http://www.google.com"); 
      dr["Result"] = string.Empty; 
      urls.Rows.Add(dr); 
      dr = urls.NewRow(); 
      dr["Srl"] = "3"; 
      dr["Urls"] = new Uri("http://www.stackoverflow.com"); 
      dr["Result"] = string.Empty; 
      urls.Rows.Add(dr); 
      urls.AcceptChanges(); 
     } 
     void UpdateResult() 
     { 
      dataGridView1.DataSource = urls; 
     } 

     //Important 
     // This example will freeze UI. You can avoid this while implementing 
     //background worker or pool with some event synchronization. I haven't covered those area since 
     //we are addressing different issue. Let me know if you would like to address UI freeze 
     //issue. Or can do it your self. 
     private void button1_Click(object sender, EventArgs e) 
     {    
      //Create array for Task to parallelize multiple download. 
      var tasks = new Task<string[]>[urls.Rows.Count]; 
      //Initialize those task based on number of Uri's 
      for(int i=0;i<urls.Rows.Count;i++) 
      { 
       int index = i;//Do not change this. This is to avoid data race 
       //Assign responsibility and start task. 
       tasks[index] = new Task<string[]>(
         () => checkSite(
          new TaskInput(urls.Rows[index]["Urls"].ToString(), urls.Rows[index]["Srl"].ToString()))); 
       tasks[index].Start(); 

      } 
      //Wait for all task to complete. Check other overloaded if interested. 
      Task.WaitAll(tasks); 

      //block shows how to access result from task 
      foreach (var item in tasks) 
      { 
       DataRow[] rows=urls.Select("Srl='"+item.Result[2]+"'"); 
       foreach (var row in rows) 
         row["Result"]=item.Result[0]+"|"+item.Result[1]; 
      } 
      UpdateResult(); 
     } 
     //This is dummy method which in your case 'Check Site'. You can have your own 
     string[] checkSite(TaskInput input) 
     { 
      string[] response = new string[3]; 
      if (input != null) 
      { 
       try 
       { 
        WebResponse wResponse = WebRequest.Create(input.Url).GetResponse(); 

        response[0] = wResponse.ContentLength.ToString(); 
        response[1] = wResponse.ContentType; 
        response[2] = input.Srl; 
        return response; 
       } 
       catch (Exception he) 
       { 
        response[0] = "catch"; 
        response[1] = he.Message; 
        response[2] = input.Srl; 
        return response; 
       } 
      } 
      response[0] = "catch"; 
      response[1] = "No URL entered"; 
      response[2] = input.Srl; 
      return response; 
     } 

     private void Form1_Load(object sender, EventArgs e) 
     { 
      InitTable(); 
      UpdateResult(); 
     } 
    } 
    //Supply custom object for simplicity 
    public class TaskInput 
    { 
     public TaskInput(){} 
     public TaskInput(string url, string srl) 
     { 
      Url = url; 
      Srl = srl; 
     } 
     public string Srl { get; set; } 
     public string Url { get; set; } 
    } 
} 
+0

謝謝,但那不是我想要做的(我不想下載文件)。 – funerr

+0

@ agam360:下載只是爲了模擬您的場景,而不是解決您的問題。我的問題的答案可以在button1_Click事件處理程序中找到,這顯然表明如何在獲取結果之前等待多個任務完成。 –