C# 将BackgroundWorker转换为异步
我曾经厌倦使用BackgroundWorker,因为它需要很多功能才能正常工作。然而,当我从VB.NET切换到C#时(大约一个月前),我偶然发现了一种非常简单的方法来实例化它们 榜样C# 将BackgroundWorker转换为异步,c#,asynchronous,async-await,C#,Asynchronous,Async Await,我曾经厌倦使用BackgroundWorker,因为它需要很多功能才能正常工作。然而,当我从VB.NET切换到C#时(大约一个月前),我偶然发现了一种非常简单的方法来实例化它们 榜样 private void cmdMaxCompressPNG_Click(object sender, EventArgs e) { pbStatus.Maximum = lstFiles.Items.Count; List<string> FileList = Load_Listbo
private void cmdMaxCompressPNG_Click(object sender, EventArgs e) {
pbStatus.Maximum = lstFiles.Items.Count;
List<string> FileList = Load_Listbox_Data();
var bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.DoWork += delegate {
foreach (string FileName in FileList) {
ShellandWait("optipng.exe", String.Format("\"{0}\"", FileName));
bw.ReportProgress(1);
}
};
bw.ProgressChanged += (object s, ProgressChangedEventArgs ex) => {
pbStatus.Value += 1;
};
bw.RunWorkerCompleted += delegate {
lstFiles.Items.Clear();
pbStatus.Value = 0;
MessageBox.Show(text: "Task Complete", caption: "Status Update");
};
bw.RunWorkerAsync();
}
在阅读了更多内容后,我开始使用Task.Run()
在->
在这里->原始代码一次只处理一个文件,因此您可以使用一个简单的循环,只异步执行
ShellandAwait
:
private void cmdMaxCompressPNG_Click(object sender, EventArgs e)
{
pbStatus.Maximum = lstFiles.Items.Count;
var FileList = Load_Listbox_Data();
foreach (var FileName in FileList)
{
//Only thing that needs to run in the background
await Task.Run(()=>ShellandWait("optipng.exe", String.Format("\"{0}\"", FileName));
//Back in the UI
pbStatus.Value += 1;
}
};
lstFiles.Items.Clear();
pbStatus.Value = 0;
MessageBox.Show(text: "Task Complete", caption: "Status Update");
如果修改了ShellandWait
,使它*不阻塞,那就更好了。我想它是用来阻挡的。方法应该异步等待,而不是侦听事件。此类事件可以转换为任务,如中所示
该方法将如下所示:
Task<string> ShellAsync(string commandPath,string argument)
{
var tcs = new TaskCompletionSource<string>();
var process = new Process();
//Configure the process
//...
process.EnableRaisingEvents = true;
process.Exited += (s,e) => tcs.TrySetResult(argument);
process.Start();
return tcs.Task;
}
我会考虑用微软的反应框架来做这件事。我认为它比使用任务更强大
private void cmdMaxCompressPNG_Click(object sender, EventArgs e)
{
pbStatus.Maximum = lstFiles.Items.Count;
var query =
from FileName in Load_Listbox_Data().ToObservable()
from u in Observable.Start(() =>
System.Diagnostics.Process
.Start("optipng.exe", String.Format("\"{0}\"", FileName))
.WaitForExit())
select u;
query
.ObserveOn(this) //marshall back to UI thread
.Subscribe(
x => pbStatus.Value += 1,
() =>
{
lstFiles.Items.Clear();
pbStatus.Value = 0;
MessageBox.Show(text: "Task Complete", caption: "Status Update");
});
}
只需获取“System.Reactive.Windows.Forms”,并使用System.Reactive.Linq添加
代码>让它工作。检查这个答案:我使用了任务、功能和动作来实现它。看看这个。ShellandWait是做什么的?既然您运行了外部进程,为什么要阻止等待它们中的每一个呢?您也可以在vb.net
中做同样的事情……我正在UI线程之外同步运行ShellandWait。我通常运行的进程是长时间运行且CPU密集型的(想想7zip)。同时运行它们会很快使系统崩溃,因为我一次运行数百到数千个进程。VB.NET可以做C所能做的一切。大多数文档都是针对C语言的,所以为了便于文档的编写,我做了一些尝试。这不是一个好的解决方案,而且太冗长了-。Invoke()
将在UI线程上运行,那么为什么要将其放在任务中呢?如果要运行外部进程,为什么要使用此代码?默认情况下,这些进程将并行运行<应修改代码>ShellandWait
,使其不会阻塞。至于异步进度报告,已经有这样一个类,progress
。检查是否有良好的描述。顺便说一句,Task.Run async的更新进度条的答案是错误的,如果UI线程中有其他内容,则很容易导致死锁。正确且投票最多的答案使用进度。在执行任务之前,人们使用BeginInvoke而不是Invoke来避免UI线程繁忙时的阻塞和等待。这实际上非常简单。我已经将长时间运行的函数转换为使用它。我仍然可以在边缘情况下使用“wait Task.Run(()=>)。
private void cmdMaxCompressPNG_Click(object sender, EventArgs e)
{
pbStatus.Maximum = lstFiles.Items.Count;
var FileList = Load_Listbox_Data();
foreach (var FileName in FileList)
{
//Only thing that needs to run in the background
await Task.Run(()=>ShellandWait("optipng.exe", String.Format("\"{0}\"", FileName));
//Back in the UI
pbStatus.Value += 1;
}
};
lstFiles.Items.Clear();
pbStatus.Value = 0;
MessageBox.Show(text: "Task Complete", caption: "Status Update");
Task<string> ShellAsync(string commandPath,string argument)
{
var tcs = new TaskCompletionSource<string>();
var process = new Process();
//Configure the process
//...
process.EnableRaisingEvents = true;
process.Exited += (s,e) => tcs.TrySetResult(argument);
process.Start();
return tcs.Task;
}
foreach (var FileName in FileList)
{
await ShellAsync("optipng.exe", String.Format("\"{0}\"", FileName));
//Back in the UI
pbStatus.Value += 1;
}
private void cmdMaxCompressPNG_Click(object sender, EventArgs e)
{
pbStatus.Maximum = lstFiles.Items.Count;
var query =
from FileName in Load_Listbox_Data().ToObservable()
from u in Observable.Start(() =>
System.Diagnostics.Process
.Start("optipng.exe", String.Format("\"{0}\"", FileName))
.WaitForExit())
select u;
query
.ObserveOn(this) //marshall back to UI thread
.Subscribe(
x => pbStatus.Value += 1,
() =>
{
lstFiles.Items.Clear();
pbStatus.Value = 0;
MessageBox.Show(text: "Task Complete", caption: "Status Update");
});
}