Pertanyaan Menjalankan BackgroundWorker dalam BackgroundWorker lain


Saya sedang mencoba tugas yang sangat intensif DB dalam sebuah proyek. Berikut ini panduannya:

Kami perlu mencari DB pekerja kami, kami disebut Locums, dan menemukan satu untuk pekerjaan tertentu. Prosedur ini dimulai ketika kami memutuskan untuk memproses x jumlah pekerjaan. Jadi, pada klik tombol, kami memproses menggunakan ProcessJobBatch() metode. Namun, metode ini hanya memproses terhadap jumlah Locums yang sangat terbatas. Jadi dibutuhkan kurang dari 10 detik untuk mengisi kontrol scheduler. Sekarang, setelah jumlah Locums yang terbatas disajikan, kita perlu menjalankan tugas latar belakang untuk memeriksa sisa Locrum. Ada sekitar 1250 dari mereka!

Jadi, sekali ProcessJobBatch() selesai, a BackgroundWorker, BackgroundWorkerMoreLocums, mati. Sekarang, pekerja ini pada dasarnya melakukan perulangan sederhana: Untuk setiap pekerjaan, kunjungilah seluruh 1250 karyawan. Ini terlalu lama. Saya perlu merencanakan ini dengan menggunakan strategi alternatif yang saya tidak dapat dari ATM atau saya perlu menunjukkan progress bar sekunder untuk bagian dalam untuk setiap loop.

Penjelasan Lebih Lanjut: Kami mengimpor sekumpulan Pekerjaan (10 hingga 70) berkali-kali pada basis harian. Setelah batch diimpor, aplikasi menginstruksikan pengguna yang masuk ke dalam "Preferensi Temukan" pekerjaan yang baru dibuat tersebut. Pengguna sudah memiliki daftar locum favoritnya (1 hingga 20). Dia ingin mendistribusikan pekerjaan di antara favoritnya dulu. Itu dilakukan melalui ProcessJobBatch(). Namun, ada dua skenario yang mencegah aliran di sana dan kemudian:

  • Bagaimana jika pekerjaan tertentu tidak jatuh setiap locum favorit?
  • Bagaimana jika ada lokum secara keseluruhan DB yang bisa melakukan hampir semua pekerjaan tetapi Karena dia bukan favorit?

Jadi, saya berakhir dengan skenario pencocokan pekerjaan dengan masing-masing Locum.

Pertanyaan:  Dapatkah kedua BackgroundWorker berjalan dalam DoWork BackgroundWorker? Apakah saya melakukan pemindaian kedua yang salah?

Lingkungan Hidup: Windows 7 Pro 64-bit, Visual Studio 2010, C #, .NET 4.0, dan Formulir Windows

    private void ButtonPreferenceFind_Click(object sender, EventArgs e) {
        if (LookUpBatches.EditValue != null) {
            JobBatch JobBatchSelected = DbContext.JobBatches.FirstOrDefault(job_batch=> job_batch.OID == LookUpBatches.EditValue.ToString());

            if (JobBatchSelected != null && JobBatchSelected.Jobs.Count(condition => condition.JobStatusID == 1) > 0) {
                if (XtraMessageBox.Show(String.Format("Are you sure to process {0} job(s)?", JobBatchSelected.Jobs.Count(condition => condition.JobStatusID == 1)), Text, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) {
                    ProcessJobBatch(JobBatchSelected);

                    IEnumerable<Job> SpecificJobs = from req_jobs in JobBatchSelected.Jobs
                                                                                    where req_jobs.JobStatusID == 1
                                                                                    select req_jobs;

                    ProgressBarControlPreferenceFinder.EditValue = 0;
                    ProgressBarControlPreferenceFinder.Properties.Minimum = 0;
                    ProgressBarControlPreferenceFinder.Properties.Maximum = SpecificJobs.Count() - 1;

                    BackgroundWorkerMoreLocums.RunWorkerAsync(SpecificJobs);

                } else {
                    LookUpBatches.Focus();
                }

            } else {
                XtraMessageBox.Show("Unable to retrieve the selected batch or the batch has no processable jobs.", Text, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                LookUpBatches.Focus();

            }

        } else {
            XtraMessageBox.Show("Select a batch first.", Text, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);                   
            LookUpBatches.Focus();

        }
    }

    #region Background Searching
    private void BackgroundWorkerMoreLocums_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e) {
        try {
            e.Result = GetTableData(e.Argument);

        }
        catch (Exception ex) {
            XtraMessageBox.Show("Background Error: " + ex.Message, "Excite Engine 2", MessageBoxButtons.OK, MessageBoxIcon.Error);
            e.Result = ex;
        }
    }

    private void BackgroundWorkerMoreLocums_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e) {
        // only display progress, do not assign it to grid          
        ProgressBarControlPreferenceFinder.Increment(e.ProgressPercentage);
    }

    private void BackgroundWorkerMoreLocums_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e) {
        if (e.Result is DataTable) {
            //dataGridView1.DataSource = e.Result as DataTable;
        }
        else if (e.Result is Exception) {
        }
    }

    private DataTable GetTableData(Object JobList) {
        DataTable ResultDataTable = new DataTable();
        ResultDataTable.Columns.Add();


        IEnumerable<Job> JobBatchSelected = (IEnumerable<Job>)JobList;

        IEnumerable<Locum> LeftOverLocums = from lefties in DbContext.Locums
                                                                                //where SchedulerMatrixStorage.Resources.Items.Select(res => (long)res.Id).ToList().Contains(lefties.OID) == false
                                                                                select lefties;

        int NumOfJobsProcessed = 0;

        List<KeyValuePair<long, TemporaryPreferenceFindLocum>> AlreadyPrefferedLocums = new List<KeyValuePair<long, TemporaryPreferenceFindLocum>>();

        foreach (Job oneJob in JobBatchSelected) {

            foreach (Locum oneLocum in LeftOverLocums) {

                if (DbContext.Availabilities.Any(check => check.LocumID == oneLocum.OID && check.AvailableDate == oneJob.JobDate && check.AvailabilityStatusID == 1)) {
                    //This Locum can do this job

                    //Now check if he/she has been just alloted
                    if (AlreadyPrefferedLocums.Any(search => search.Key == oneLocum.OID && search.Value.JobDate == oneJob.JobDate) == false) {
                        //No? Cool!                     
                        //Add to the list to prevent double allocation
                        AlreadyPrefferedLocums.Add(new KeyValuePair<long, TemporaryPreferenceFindLocum>(oneJob.OID, new TemporaryPreferenceFindLocum(oneJob.JobDate, oneJob.OID, oneLocum.OID, oneLocum.FirstName + " " + oneLocum.LastName)));

                    }
                    else {
                        continue;

                    }

                }
                else {
                    //Not marked as Avaliable on the required job date...
                    continue;

                }

            }

            NumOfJobsProcessed++;
            BackgroundWorkerMoreLocums.ReportProgress((int)(NumOfJobsProcessed * 100F / (JobBatchSelected.Count() - 1)));
        }

        return ResultDataTable;
    }
    #endregion

5
2018-03-09 10:39


asal


Jawaban:


SEBUAH BackgroundWorker dapat dimulai dari dalam DoWork pawang yang lain BackgroundWorker, tetapi Anda perlu menyadari konsekuensi menggunakan skema tersebut. Ketika Anda memulai pekerja latar belakang dari UI utas utama Anda DoWork handler dieksekusi pada thread kolam thread sementara ProgressChanged dan RunWorkerCompleted dieksekusi kembali pada utas UI utama sehingga aman bagi Anda untuk berinteraksi dengan bentuk kontrol windows.

Skenario ini dijamin ketika Anda memulai pekerja dari utas UI utama karena mengambil SynchronizationContext tersedia di thread itu dan yang diinisialisasi oleh windows membentuk infra-struktur.

Namun, ketika Anda memulai pekerja latar belakang dari DoWork pawang pekerja lain, Anda akan memulainya dari utas ulir utas yang tidak memiliki konteks sinkronisasi yang menyebabkan ProgressChanged dan RunWorkerCompleted handler juga dieksekusi pada thread pool thread dan tidak di thread UI utama Anda membuatnya tidak aman bagi Anda untuk berinteraksi dengan bentuk-bentuk windows kontrol dari dalam handler tersebut.


11
2018-03-09 11:14



Sangat umum untuk memiliki satu latar belakang thread menelurkan benang latar belakang baru. Saya tidak berpikir itu adalah masalah jika Anda memindai daftar pada utas latar belakang dan memproses setiap item daftar pada utas lain.

Dalam kasus seperti itu tidak ada pekerja latar belakang dalam lain. Hanya ada pekerja latar yang memulai utas lainnya.

Hal-hal yang harus Anda pertimbangkan -

  1. Sadarilah apa yang Anda lakukan dalam penangan kejadian yang telah selesai jika Anda menangani peristiwa itu.

  2. Pertimbangkan implikasi kinerja menjalankan begitu banyak untaian untuk tugas-tugas kecil. Anda harus mempertimbangkan menggunakan Tugas PLINQ atau paralel sehingga. Net dapat menangani pembagian input dan penggabungan hasil yang memberi Anda kinerja optimal.


5
2018-03-09 11:31