SwethaVijayan Ответов: 1

Темы с backgroundworker, ждет долгое время . Как я могу этого избежать


я использую поток с BackGroundWorker по этому, приложение ждет в течение длительного времени, чтобы получить 50000 записей, это делает другую операцию, чтобы дождаться завершения этого потока. как я могу избежать процесса ожидания при использовании потока?

Что я уже пробовал:

private void btnExrtPDF_Click(object sender, RoutedEventArgs e)
     {
         if (DetailsOrSummary == "Details")
             isDetails = true;


         Dispatcher.BeginInvoke(DispatcherPriority.Input, new ThreadStart(() =>
         {
             try
             {
                 DetailReportFCBuySell = AlyexWCFService.DL.DLTTIn.FCBuySELL(transactionName, isDetails, Convert.ToDateTime(dateEdtStartDate.EditValue).Date, Convert.ToDateTime(dtpEditEndDate.EditValue).Date, Customerid, ProductID, branchID, NoOfRecords, PageIndex - 1, isBuy);
                 worker.RunWorkerAsync();
             }
             catch
             {

                 object obj = new object();

             }
         }

         ));
}

 private void worker_DoWork(object sender, DoWorkEventArgs e)
     {

         Dispatcher.Invoke(new Action(() => {
         System.Data.DataTable batchFCSB = new System.Data.DataTable();
         int row = 0;


         if (DetailReportFCBuySell.FirstOrDefault().TotalRecords > toFetchRecords)
         {

            // long RecordsIcrease = 10000;
             long RecordsIcrease = 1000;
             batchFCSB = DetailReportFCBuySell.ToDataTable();
             //Collection.Add(row, batchFCSB);
             row = 1;
             PageIndex++;

             for (long k = toFetchRecords; k < DetailReportFCBuySell.FirstOrDefault().TotalRecords; k = +toFetchRecords)
             {

                 new AlxServiceClient().Using(channel =>
                 {

                     ObservableCollection<dlreports.fcbuyselldetail> temp = AlyexWCFService.DL.DLTTIn.FCBuySELL(transactionName, isDetails, Convert.ToDateTime(dateEdtStartDate.EditValue).Date, Convert.ToDateTime(dtpEditEndDate.EditValue).Date, Customerid, ProductID, branchID, NoOfRecords, PageIndex - 1, isBuy);
                     DetailReportFCBuySell = DetailReportFCBuySell.Union(temp).ToObservableCollection();

                     row++;
                     PageIndex++;

                 });
                 toFetchRecords = toFetchRecords + RecordsIcrease;
             }
         }
         }), DispatcherPriority.ContextIdle);
     }

1 Ответов

Рейтинг:
0

Richard Deeming

Вы используете BackgroundWorker чтобы подтолкнуть работу к фоновому потоку. Но вы тут же звоните Dispatcher.Invoke чтобы вернуть работу обратно в поток пользовательского интерфейса.

В результате вы блокируете поток пользовательского интерфейса до тех пор, пока ваша работа не завершится, и оставляете фоновый поток бездействующим, ожидая, пока ваш поток пользовательского интерфейса закончит свою работу.

Вам нужно переместить как можно больше работы в фоновый поток. Снимите наружный Dispatcher.Invoke позвоните в свой worker_DoWork метод. Когда вам нужно обновить пользовательский интерфейс, используйте ReportProgress метод передачи данных обратно в поток пользовательского интерфейса.

Предполагая, что он обновляет DetailReportFCBuySell свойство, которое должно произойти в потоке пользовательского интерфейса, должно работать примерно так:

private void worker_DoWork(object sender, DoWorkEventArgs e)
{
    var batchFCSB = new System.Data.DataTable();
    int row = 0;

    if (DetailReportFCBuySell.FirstOrDefault().TotalRecords > toFetchRecords)
    {
        long RecordsIcrease = 1000;
        batchFCSB = DetailReportFCBuySell.ToDataTable();
        row = 1;
        PageIndex++;
        
        for (long k = toFetchRecords; k < DetailReportFCBuySell.FirstOrDefault().TotalRecords; k = +toFetchRecords)
        {
            new AlxServiceClient().Using(channel =>
            {
                var temp = AlyexWCFService.DL.DLTTIn.FCBuySELL(transactionName, isDetails, Convert.ToDateTime(dateEdtStartDate.EditValue).Date, Convert.ToDateTime(dtpEditEndDate.EditValue).Date, Customerid, ProductID, branchID, NoOfRecords, PageIndex - 1, isBuy);
                worker.ReportProgress(0, temp);
                row++;
                PageIndex++;
            });
            
            toFetchRecords = toFetchRecords + RecordsIcrease;
        }
    }
}

private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    var temp = (ObservableCollection<dlreports.fcbuyselldetail>)e.UserState;
    DetailReportFCBuySell = DetailReportFCBuySell.Union(temp).ToObservableCollection();
}

NB: Вам нужно будет установить worker.WorkerReportsProgress собственность на true, и провод вверх по worker_ProgressChanged метод к worker.ProgressChanged событие.


SwethaVijayan

Вызывающий поток не может получить доступ к этому объекту, поскольку он принадлежит другому потоку.

эта ошибка обнаружена с помощью avoid the dispacher

Richard Deeming

Так что, как я уже сказал, двигайтесь просто код, который получает доступ / обновляет пользовательский интерфейс к потоку пользовательского интерфейса.

Если вы используете диспетчер для перемещения всего worker_DoWork функция возвращается в поток пользовательского интерфейса, тогда вы можете с таким же успехом не утруждать себя использованием BackgroundWorker во-первых.

SwethaVijayan

чтобы избежать этого, что я должен сделать. мне нужно избегать применения waing в течение длительного времени. пожалуйста, дайте мне подходящий ответ .

Richard Deeming

Как я вам уже говорил, переместите как можно больше кода в фоновый поток. Только код, который обращается к пользовательскому интерфейсу или обновляет его, должен быть возвращен обратно в поток пользовательского интерфейса.

Я уже дал вам "подходящий ответ"; вам просто нужно прочитать и понять его.

SwethaVijayan

я должен был удалить диспетчера, как вы сказали в моей программе, и я сделал это другим способом.

частная btnExrtPDF_Click недействительным(объект отправителя, RoutedEventArgs е)
{


if (DetailsOrSummary = = " подробности")
isDetails = истина;
//FetchRecord();
// Task myFirstTask = задача.Factory.StartNew(FetchRecord);
lblStatus.Text = ("Прогресс:" + 0 + "%");
thread = new Thread(new ThreadStart(FetchRecord));

нить.Начать();

}


частный недействительными FetchRecord()
{
пробовать
{
если (приложение.Текущий.Диспетчер.Метод checkaccess())
{
if (DetailsOrSummary = = " подробности")
isDetails = истина;


DetailReportFCBuySell = AlyexWCFService.DL.DLTTIn.FCBuySELL(transactionName, isDetails, Convert.Объект todatetime(dateEdtStartDate.EditValue).Дата, Конвертация.Объект todatetime(dtpEditEndDate.EditValue).Дата, Customerid, ProductID, branchID, NoOfRecords, PageIndex-1, isBuy);
long RecordsIcrease = 1000;
Pageindex было++;

for (long k = toFetchRecords; k & lt; DetailReportFCBuySell.Метода firstordefault().TotalRecords; k = +toFetchRecords)
{

новый AlxServiceClient (). Using(channel = & gt;
{
ObservableCollection< DLReports.FCBuySellDetail> temp = AlyexWCFService.DL.DLTTIn.FCBuySELL(transactionName, isDetails, Convert.Объект todatetime(dateEdtStartDate.EditValue).Дата, Конвертация.Объект todatetime(dtpEditEndDate.EditValue).Дата, Customerid, ProductID, branchID, NoOfRecords, PageIndex-1, isBuy);
DetailReportFCBuySell = DetailReportFCBuySell.Союз (temp).ToObservableCollection();
Pageindex было++;
});
toFetchRecords = toFetchRecords + RecordsIcrease;
}

ResultsData = DetailReportFCBuySell.ToDataTable ();// (Коллекция.Где (i => i. Key == k).FirstOrDefault (). Value);
ExportToOxml(правда);
}
ещё
{
// Другой мудрый повторный вызов метода с доступом к потоку пользовательского интерфейса
Приложение.Текущий.Диспетчер.Invoke (новая система.Действие (() = & gt; FetchRecord()));
}
}
поймать (исключение бывший)
{
бросок экс;
}
}


таким образом, я также получаю ту же ошибку, что и приложение, ожидающее 30 секунд

Richard Deeming

Нет! Вы все еще передача всей работы обратно в поток пользовательского интерфейса.

Вы запускаете новый фоновый поток для выполнения FetchRecord метод. Затем этот метод вызывает CheckAccess, который возвращается false поскольку вы находитесь в фоновом потоке. Затем метод вызывает Invoke чтобы вызвать метод в потоке пользовательского интерфейса.

Опять же, вы блокируете поток пользовательского интерфейса до тех пор, пока ваш метод не завершится, и оставляете фоновый поток бездействующим, ожидая, пока поток пользовательского интерфейса завершит выполнение вашего метода.

Вам нужна трудоемкая работа для запуска в фоновом потоке. Он должен перезванивать в поток пользовательского интерфейса только тогда, когда ему нужно получить доступ к пользовательскому интерфейсу или обновить его.

Если вы собираетесь продолжать толкать все обратно в поток пользовательского интерфейса, то вы можете вообще не использовать фоновый поток.

То, что вы делаете, по сути, то же самое, что нанять помощника, который поможет вам сделать больше работы. Но каждый раз, когда вы даете работу своему помощнику, он просит вас сделать это за него, сидит и ждет, пока вы закончите. Когда вы закончите выполнять его работу, вы передаете ему результаты, а он затем возвращает их вам и говорит: "работа сделана" Вы не успеваете сделать больше никакой работы, а ваш помощник (фоновый поток) совершенно бесполезно.

SwethaVijayan

хорошо, я понял проблему, но как я могу это сделать ,пожалуйста, помогите мне.

Richard Deeming

Еще раз: выполняйте работу в фоновом потоке и только вызывайте Invoke когда вам нужно получить доступ или обновить пользовательский интерфейс.

Начните с того, что не звоните никому. Invoke. Когда вы получите "вызывающий поток" исключение, посмотрите на стек вызовов, чтобы увидеть, к чему вы пытаетесь получить доступ. Подвиньте этот конкретный бит вашего кода в Invoke позвони и попробуй еще раз. Повторяйте до тех пор, пока код не будет работать без исключения.

И помните, что использование фонового потока не ускорит ваш код; он просто сохранит пользовательский интерфейс отзывчивым, пока ваш код работает.

SwethaVijayan

можете ли вы привести один пример со мной?

Richard Deeming

Если вы используете BackgroundWorker, и вам нужно только обновить пользовательский интерфейс, а затем ReportProgress будет делать свою работу - как я написал в своем ответе.

Для всего остального используйте Dispatcher.Invoke во исполнение конкретный фрагмент кода в потоке пользовательского интерфейса.