多个并行未定义的BackgroundWorker [重复]
Posted
技术标签:
【中文标题】多个并行未定义的BackgroundWorker [重复]【英文标题】:Multiple parallel undefined BackgroundWorker [duplicate] 【发布时间】:2021-09-23 07:57:39 【问题描述】:我使用BackgroundWorker
复制Zip archive
(获取进度的3td 部件库)中的文件,因此我不会阻塞UI,我可以升级ProgressBar
或取消复制。
这是BackgroundWorker
的代码,source、target和name是通用变量:
private void _backgroundWorkerB1_DoWork(object sender, DoWorkEventArgs e)
try
//Check if the source directory exist
if (Directory.Exists(source) == false)
e.Result = "NotExist";
return;
//If the target not exist I will create it
if (Directory.Exists(target) == false)
Directory.CreateDirectory(target);
string filename = target + "\\" +
DateTime.Now.ToString("yyyy'-'MM'-'dd'_'HH'_'mm'_'ss") +
"-" + name + ".zip";
// 3td part library
ArchivioB1.FileName = filename;
ArchivioB1.OpenArchive(System.IO.FileMode.Create);
ArchivioB1.OnOverallProgress += new BaseArchiver
.OnOverallProgressDelegate(ArchivioB1_OnOverallProgress);
// Source directory
ArchivioB1.BaseDir = source;
// Copy all files
ArchivioB1.AddFiles("*.*");
// Close
ArchivioB1.CloseArchive();
catch (Exception ex)
e.Result = "Error";
return;
我需要修改代码以使其与DataGrid
并行。我将在第一列有一个DataGrid
,在第一列是文件名,在第二列是进度条,在第三列是状态,在第四列是文件的目的地。
DataGrid
可以有未定义的行,这些行可以超过 CPU 的核心。如何并行运行相同的函数,如果行数超过 CPU 内核,系统必须等待其中一个空闲并继续下一个副本?
我不明白为什么社区必须在没有像他们想象的那样重复时关闭问题,无论如何,如果有人需要与进度并行复制存档中的文件 此后使用工作代码进行最终编辑:
private async void btBackup_Click(object sender, RoutedEventArgs e)
btBackup.IsEnabled = false;
btCancel.IsEnabled = true;
var row_list1 = GetDataGridRows(dgwStation);
List<Task> tasks = new List<Task>();
ZipForge[] ZipList = new ZipForge[DataGridItemsList.Count];
tokenSource = new CancellationTokenSource();
foreach (DataGridRow single_row in row_list1)
int riga = single_row.GetIndex();
ZipList[riga] = new ZipForge();
tasks.Add(Task.Run(() => CopyTest(riga,ZipList[riga])));
await Task.WhenAll(tasks);
if (generalerror)
tbkStato.Text = "Completed with error";
else if (tbkStato.Text != "Cancelled")
tbkStato.Text = "Completed";
private void btCancel_Click(object sender, RoutedEventArgs e)
try
if (tokenSource != null) //se il token non è nullo, posso chiedere la cancellazione
//tbkStato.Text = "Cancelled";
tokenSource.Cancel();
catch (Exception ex)
MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
public void CopyTest(int rowindex, ZipForge ArchivioB1)
string nome1 = "";
try
//Takes data from DatGridItemsList
string source = DataGridItemsList[rowindex].Source, target = DataGridItemsList[rowindex].Target, filename = DataGridItemsList[rowindex].FileName;
tbkStato.Dispatcher.Invoke(new Action(() => tbkStato.Text = "Check source"; ));
if (Directory.Exists(source) == false)
DataGridItemsList[rowindex].State = "Not Exist";
dgwStation.Dispatcher.Invoke(new Action(() => dgwStation.Items.Refresh(); ));
generalerror = true;
return;
tbkStato.Dispatcher.Invoke(new Action(() => tbkStato.Text = "Check target"; ));
if (Directory.Exists(target) == false)
Directory.CreateDirectory(target);
DataGridItemsList[rowindex].State = "creating Zip";
dgwStation.Dispatcher.Invoke(new Action(() => dgwStation.Items.Refresh(); ));
nome1 = target + "\\" + DateTime.Now.ToString("yyyy'-'MM'-'dd'_'HH'_'mm'_'ss") + "-" + filename + ".zip";
ArchivioB1.FileName = nome1;
ArchivioB1.OpenArchive(System.IO.FileMode.Create,FileAccess.Write);
ArchivioB1.Comment = rowindex.ToString();
ArchivioB1.OnOverallProgress += new BaseArchiver.OnOverallProgressDelegate(ArchivioB1_OnOverallProgress);
ArchivioB1.BaseDir = source;
// Copia tutti i file nell'archivio creato
ArchivioB1.AddFiles("*.*");
if (tokenSource.Token.IsCancellationRequested) //Interruzzione dell'utente
tokenSource.Token.ThrowIfCancellationRequested();
else
ArchivioB1.CloseArchive();
DataGridItemsList[rowindex].State = "Completed";
dgwStation.Dispatcher.Invoke(new Action(() => dgwStation.Items.Refresh(); ));
catch (OperationCanceledException)
ArchivioB1.CloseArchive();
if (File.Exists(nome1))
File.Delete(nome1);
DataGridItemsList[rowindex].State = "Cancelled";
dgwStation.Dispatcher.Invoke(new Action(() => dgwStation.Items.Refresh(); ));
tbkStato.Dispatcher.Invoke(new Action(() => tbkStato.Text = "Cancelled"; ));
return;
catch (Exception ex)
ArchivioB1.CloseArchive();
if (File.Exists(nome1))
File.Delete(nome1);
DataGridItemsList[rowindex].State = ex.Message.ToString();
dgwStation.Dispatcher.Invoke(new Action(() => dgwStation.Items.Refresh(); ));
generalerror = true;
return;
private void ArchivioB1_OnOverallProgress(object sender, double progress, TimeSpan timeElapsed, TimeSpan timeLeft, ProcessOperation operation, ProgressPhase progressPhase, ref bool cancel)
if (tokenSource.Token.IsCancellationRequested) //Interruzzione dell'utente
cancel = true;
//tokenSource.Token.ThrowIfCancellationRequested();
ZipForge Archivio = (ZipForge)sender;
int indice = Convert.ToInt32(Archivio.Comment);
DataGridItemsList[indice].Progress = Convert.ToInt32(progress);
dgwStation.Dispatcher.Invoke(new Action(() => dgwStation.Items.Refresh(); ));
【问题讨论】:
你也可以去how can I limit parallel-foreach看看 @Clemens 这个问题与that 问题有什么关系?这个问题与异步操作无关,而且这些操作也不太可能完全受 I/O 限制。归档文件也可能非常受 CPU 限制。 Paolo 您能否在问题中包含ArchivioB1_OnOverallProgress
事件处理程序?
所以也可能有一个_backgroundWorkerB1_ProgressChanged
事件处理程序。你能把它包括在问题中吗?我们必须查看您当前更新DataGrid
的方式和位置,否则我们如何提供帮助?
@TheodorZoulias 在BackgroundWorker
中,我只是更新了一般的ProgressBar
和TextBlock
。我需要修改代码以并行运行以升级DataGrid
【参考方案1】:
我建议使用 Tasks 而不是 Backgroundworkers。您可以使用 Task.WhenAll... 以简单的方式运行任意数量的 Tasks...
如果您想同步执行任务,只需省略 await
...
public async ExecuteMultipleTasksSimultaneously()
List<Task> tasks = new List<Task>()
Task.Factory.StartNew(() => ActionA()),
Task.Factory.StartNew(() => ActionB()),
Task.Factory.StartNew(() => ActionC())
;
//Execute all tasks "at the same time"...
await Task.WhenAll(tasks);
// or await Task.WhenAny(tasks);
// or await Task.WaitAll(tasks)
//or Task.WaitAny(tasks) depending on your execution needs
// Continue on this thread...
//Alternative to Task.Factory.StartNew(() => ActionA()) you could use
// Task.Run(()=> ActionA())
我希望这指明了正确的方向。最好的问候。
【讨论】:
我需要多次启动同一个Action,我只是改变源和目标,因为代码会做同样的事情。我编辑了我的问题,您可以在其中看到我用来测试的代码,但最终结果不是我所表达的 只需为动作提供不同的参数。您也可以在不等待结果的情况下启动任务。只需调用 Task.Run(()=> SameAction(differentparameters)。要从后台操作更新 UI,请使用 App.Current.Dispatcher.Invoke(() => UpdateUIFunction()); 太多操作更新 UI 太频繁会影响(减慢)你的 UI。我建议你定期更新 UI 大约 200 毫秒或更长时间。但是,对于这类事情,我真的建议实现 MVVM 模式(绑定)。直接更新 UIcomponent 不是一个好方法去做这类事情。以上是关于多个并行未定义的BackgroundWorker [重复]的主要内容,如果未能解决你的问题,请参考以下文章
使用队列在两个 BackgroundWorker 之间传递数据
BackgroundWorker:Argument-Object 的子代