2012-03-28 39 views
3

我想通過多線程在Foreach中運行「SearchResultByOrderNumber(string orderNumber)」方法。在OrderNumbers Datatable中有十個OrderNumbers。在OrderResults Datatable中搜索這些OrderNumbers時,我想將這些OrderNumbers分成五個線程。在每個線程中都會有兩次搜索OrderNumbers。我如何使用Asp.Net 3.5 Framework進行線程化?將Foreach劃分爲線程樣本

我想,我必須重申我的問題。 如何自動將「OrderNumbers」劃分爲Async方法? 首先,我得到了rowCount。我將要定義Async方法計數。然後我將通過rowCount的劃分與asyncMethodCount得到rowsPerAsyncMethods

rowsPerAsyncMethods = rowCount/asyncMethodCount 

謝謝。

void Main() 
{ 

    var MyTask1Caller = new Func<DataTable>(MyTask1); 
    var asyncResultMyTask1 = MyTask1Caller.BeginInvoke(null, null); 
    var MyTask2Caller = new Func<DataTable>(MyTask2); 
    var asyncResultMyTask2 = MyTask2Caller.BeginInvoke(null, null); 

    DataTable dtMyTask1 = MyTask1Caller.EndInvoke(asyncResultMyTask1); 
    DataTable dtMyTask2 = MyTask2Caller.EndInvoke(asyncResultMyTask2); 
    Console.WriteLine("dtMyTask1"); 
    Console.WriteLine("dtMyTask2"); 
    asyncResultMyTask1.AsyncWaitHandle.WaitOne(); 
    asyncResultMyTask2.AsyncWaitHandle.WaitOne(); 


} 

public int RowCount() 
{ 
    DataTable dt = OrderNumbers(); 
    int items = dt.Rows.Count; 

    return items; 

} 


public DataTable MyTask1() 
{ 
    DataTable dtResult = new DataTable(); 
    DataColumn dc = new DataColumn("OrderNumber", typeof(System.Int32)); 
    dtResult.Columns.Add(dc); 
    dc = new DataColumn("OrderResult", typeof(string)); 
    dtResult.Columns.Add(dc); 

    DataTable dtOrders = new DataTable(); 
    dtOrders = OrderNumbers(); 

    var items = dtOrders.AsEnumerable() 
    .Select(n => n).Take(3).CopyToDataTable(); 

    foreach(var order in items.AsEnumerable()) 
    { 

     string orderNumber = order["OrderNumber"].ToString(); 
     string orderResult = SearchResultByOrderNumber(orderNumber); 
     DataRow dr = dtResult.NewRow(); 
     dr["OrderNumber"] = orderNumber; 
     dr["OrderResult"] = orderResult; 
     dtResult.Rows.Add(dr); 
    } 

    //Thread.Sleep(5000);  
    return dtResult; 
} 


public DataTable MyTask2() 
{ 
    DataTable dtResult = new DataTable(); 
    DataColumn dc = new DataColumn("OrderNumber", typeof(System.Int32)); 
    dtResult.Columns.Add(dc); 
    dc = new DataColumn("OrderResult", typeof(string)); 
    dtResult.Columns.Add(dc); 

    DataTable dtOrders = new DataTable(); 
    dtOrders = OrderNumbers(); 

    var items = dtOrders.AsEnumerable() 
    .Select(n => n).Skip(3).Take(3).CopyToDataTable(); 

    foreach(var order in items.AsEnumerable()) 
    { 

     string orderNumber = order["OrderNumber"].ToString(); 
     string orderResult = SearchResultByOrderNumber(orderNumber); 
     DataRow dr = dtResult.NewRow(); 
     dr["OrderNumber"] = orderNumber; 
     dr["OrderResult"] = orderResult; 
     dtResult.Rows.Add(dr); 
    } 


    return dtResult; 
} 

    public string SearchResultByOrderNumber(string orderNumber) 
    { 

     DataTable dt = new DataTable(); 
     dt = OrderResults(); 

     var query = (from n in dt.AsEnumerable() 
        where n["OrderNumber"].ToString() ==orderNumber 
        select n["OrderResult" ].ToString()).FirstOrDefault(); 
     return query; 
    } 

    public DataTable OrderResults() 
    { 

       DataTable dt = new DataTable("OrderResults"); 
       DataColumn dc = new DataColumn("OrderNumber", typeof(System.Int32)); 
       dt.Columns.Add(dc); 
       dc = new DataColumn("OrderResult", typeof(string)); 
       dt.Columns.Add(dc); 

       for(int i=1; i<10; i++) 
       { 
        DataRow dr = dt.NewRow(); 
        dr["OrderNumber"] = i; 
        dr["OrderResult"] =i +" Result"; 
        dt.Rows.Add(dr); 
       } 

       return dt; 
    } 


    public DataTable OrderNumbers() 
    { 

       DataTable dt = new DataTable("OrderNumbers"); 
       DataColumn dc = new DataColumn("OrderNumber", typeof(System.Int32)); 
       dt.Columns.Add(dc); 

       for(int i=0; i<10; i++) 
       { 
        DataRow dr = dt.NewRow(); 
        dr["OrderNumber"] = i; 
        dt.Rows.Add(dr); 
       } 

       return dt; 
    } 
+0

不能升級到.NET 4.0?它包含了對多線程的許多改進。 – svick 2012-03-28 00:53:59

+0

我的舊項目不可能升級。 – qods 2012-03-28 01:03:31

+0

您可能想查看[如何更改您的方法以運行異步](http://www.csharp-examples.net/create-asynchronous-method/),或者可能只是使用線程池來運行您的內容'as'異步。 – 2012-03-28 01:16:12

回答

2

如果.NET 4.0可用,則可以使用Parallel.ForEach構造。

如果沒有,並行處理,這是因爲使用ThreadPool類的簡單,同步一些額外的工作:

int tasks = 0; // keep track of number of active tasks 
object locker = new object(); // synchronization object 

foreach(var order1 in dtOrders.AsEnumerable()) 
{ 
    lock(locker) tasks++; // added a new task 
    var order = order1; // local copy to avoid data races 
    ThreadPool.QueueUserWorkItem(
     o => 
     {   
      string orderNumber = order["OrderNumber"].ToString(); 
      string orderResult = SearchResultByOrderNumber(orderNumber); 
      DataRow dr = dtResult.NewRow(); 
      dr["OrderNumber"] = orderNumber; 
      dr["OrderResult"] = orderResult; 

      lock(locker) // update shared data structure and signal termination 
      { 
       dtResult.Rows.Add(dr); 
       tasks--; 
       Monitor.Pulse(locker); 
      }     
     }); 
} 

// barrier to wait for all tasks to finish 
lock(locker) 
{ 
    while(tasks > 0) Monitor.Wait(locker); 
} 
+0

謝謝,我要去試試。但我必須使用.NET 3.5 – qods 2012-03-28 08:26:49

+0

@qods來實現這個目標:我發佈的代碼將與.NET 2.0及更高版本一起工作。 – Tudor 2012-03-28 08:58:54

+0

@Todor:對於遲到的回覆,抱歉。它工作得很好..現在我得到的結果是正常時間的一半。現在,我試圖用DTResult DataTable的格式將記錄插入到MS-SQL DB中,而不是DataTable。我怎樣才能用ThreadPool來管理這個? – qods 2012-03-29 13:42:30

1

您可以使用CountdownEvent這將阻止當前線程,直到計數0:

var sync = new object(); 
var cd = new CountDownEvent(dtOrders.Rows.Count); 

foreach(var order in dtOrders) 
{ 
    var dr = dtResult.NewRow(); 
    dr["OrderNumber"] = order["OrderNumber"].ToString(); 

    ThreadPool.QueueUserWorkItem(o => 
    { 
     dr["OrderResult"] = SearchResultByOrderNumber(dr["OrderNumber"].ToString()); 

     lock(sync) dtResult.Rows.Add(dr); 
     cd.Signal(); 
    }); 
} 

cd.Wait(); 
  • 的計數值被構造方法設置。
  • cd.Signal()遞減1。
  • cd.Wait()阻塞當前線程,直到計數爲0
+0

謝謝你的退潮,我要去試試。 – qods 2012-03-29 13:43:12