Разделить Foreach на образец темы - PullRequest
3 голосов
/ 28 марта 2012

Я хочу запустить метод "SearchResultByOrderNumber(string orderNumber)" в Foreach с многопоточностью.В OrderNumbers Datatable есть десять номеров заказов.При поиске этих номеров заказов в OrderResults Datatable я хочу разделить эти номера заказов на пять потоков.В каждой теме будет два поиска для OrderNumbers.Как я могу сделать это с Asp.Net 3.5 Framework?

Я думаю, я должен обновить свой вопрос.Как автоматически разделить «OrderNumbers» на асинхронные методы?Во-первых, я получил rowCount.Я собираюсь определить количество асинхронных методов.Тогда я получу rowsPerAsyncMethods делением rowCount с asyncMethodCount.

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;
    }

Ответы [ 2 ]

2 голосов
/ 28 марта 2012

Если доступен .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); 
}
1 голос
/ 28 марта 2012

Вы можете использовать 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() уменьшить счет на единицу.
  • cd.Wait() блокирует текущий поток, пока счетчик не станет равным 0.
...