我想循环无穷大以检查所有时间n = 0或n = 1
public int check()
{
int n;
Int32 nTest = 0;
nTest = RID.Read(obj);
if (nTest != 0)
{
n = 0;
}
else
{
n = 1;
}
return n;
}
private async void Form1_Load(object sender, EventArgs e)
{
Task<int> task = new Task<int>(check);
task.Start();
while (true)
{
int c = await task;
label7.Text = c.ToString();
}
}
我尝试在Form1_Load中为true时进行开始检查n值。当我运行程序时,它将冻结并且无法单击任何东西。如何解决?
答案 0 :(得分:0)
Async-await旨在阻止程序在相对较短的时间内闲置地等待另一个进程完成。考虑一下等待数据库查询结果,读取文件,从数据库中获取数据等。
如果您使用async-await,则在其他处理正在执行请求时,您的线程不会闲着等待。相反,if是否可以环顾四周,看看是否还有其他事情要做。
当然,您可以通过创建单独的线程来等待您来实现相同的效果。除此之外,这将使您的代码更加复杂,创建单独的线程非常耗时。
如果您想启动一个长时间运行的进程,想想几秒钟甚至几分钟甚至更长的时间,那么启动该单独线程所需的时间就不再重要了。
因此,根据您的情况,我建议您使用BackgroundWorker
如果后台工作人员需要很多程序来完成工作,请考虑从BackgroundWorker派生,并以BackgroundWorker.OnDoWork
的替代字词开始工作。
在您的情况下,背景工作人员仅需要一个小的功能,因此足以订阅DoWork
事件。
使用Visual Studio工具箱添加背景工,或将其手动添加到构造函数中:
// Constructor:
public Form1()
{
InitializeComponent();
// Create a backgroundworker
this.backgroundWorker = new BackgroundWorker
{
// only if you want to display something during processing:
WorkerReportsProgress = true,
WorkerSupportsCancellation = true; // to neatly close your form
};
this.backgroundWorker.DoWork += this.BackgroundProcedure;
this.backgroundWorker.ProgressChanged += this.BackgroundProcessReport;
this.backgroundWorker.RunworkerCompleted += this.BackgroundWorkerFinished;
}
启动和停止很容易:
bool IsBackGroundWorkerBusy => this.backgroundWorker.IsBusy;
void StartBackgroundWork()
{
if (this.IsBackGroundWorkerbusy) return; // already started;
this.DisplayBackgroundWorkerActive(); // for example, show an ajax loader
this.backgroundWorker.RunworkerAsync();
// or if you want to start with parameters:
MyParameters backgroundWorkerParameters = new MyParameters(...);
this.backgroundWorker.RunworkerAsync(backgroundWorkerParameters);
}
void RequestCancelBackgroundWork()
{
this.DisplayBackgroundWorkerStopping();
this.backgroundWorker.CancelAsync();
}
背景过程。它由后台线程执行。 您无法在此过程中调用任何与UI相关的功能。 如果要更新UI中的任何内容,请使用ReportProgress。
void BackGroundProcedure(object sender, DoworkEventArgs e)
{
// if you know that the backgroundworker is started with parameters:
MyParameters parameters = (MyParameters)e.Argument;
// do you work, regularly check if cancellation is requested:
while (!e.Cancel)
{
...
// only if progress reports are needed: report some progress, not too often!
MyProgressParams progressParams = new MyProgressParams(...);
this.ReportProgress(..., progressParams);
}
// if here, the thread is requested to cancel
// if needed report some result:
e.Result = ...;
}
进度报告。它由您的UI线程执行,因此,如果需要,您可以更新UI元素。这是此方法的主要功能。
报告进度中的第一个参数是一个数字,通常从0..100开始,由进度事件的接收者使用它来更新有关进度的某些可视显示。如果没有任何迹象表明进度需要多长时间,请不要使用该值。 progressParams可以是任何对象。
void BackgroundProcessReport(object sender, ProgressChangedEventArgs e)
{
// the background worker reported some progress.
... // update UI
}
线程完成后,将调用Runworker Completed 。它包含分配给e.Result的数据。它由UI线程执行,因此您可以执行任何与UI相关的工作:
void BackgroundWorkerFinished(object sender, RunWorkerCompletedEventArgs e)
{
this.DisplayBackgroundWorkerFinished(); // for example: hide ajax loader
... // use e to process result
}
如果您的表格正在关闭,则必须先完成后台工作,然后才能处理窗口。正确的方法是使用OnClosing事件:
bool closeFormRequested = false;
void OnFormClosing(object sender, CancelEventArgs e)
{
// if background worker busy: request cancellation; can't close the form right now
if (this.IsBackgroundworkerBusy)
{
this.closeFormRequested = true;
e.Cancel = true;
this.RequestCancelBackgroundWork();
}
else
{ // background worker not busy, OK to close
e.Cancel = false;
}
}
一段时间后,后台工作人员报告它已完成:
void BackgroundWorkerFinished(object sender, RunWorkerCompletedEventArgs e)
{
this.DisplayBackgroundWorkerFinished();
... // process result
// if requested: close the form:
if (this.closeFormRequested)
this.Close();
}
this.Close()
将导致OnFormClosing
,但是这次后台工作人员不会很忙,并且关闭将继续
最后:后台工作人员实现了IDisposable,不要忘了在处理表单时将其处理。
答案 1 :(得分:0)
您应该使用Microsoft的Reactive Framework(又名Rx)-NuGet System.Reactive.Windows.FOrms
并添加using System.Reactive.Linq;
-然后您可以执行以下操作:
private async void Form1_Load(object sender, EventArgs e)
{
IDisposable subscription =
Observable
.While(() => true, Observable.Start(() => RID.Read(obj) == 0 ? 1 : ))
.ObserveOn(this)
.Subscribe(c => label7.Text = c.ToString());
}
这就是您的全部代码。
答案 2 :(得分:0)
当我运行程序时,它会冻结并且无法单击任何东西。
这是因为任务仅启动一次。完成后,它会保持完成,因此第一个await
异步地等待任务完成,但是所有其他await
都只是立即并同步地返回了第一个值。这就是为什么您无法单击任何东西的原因:您最终在UI线程上出现了同步无限循环。
要解决此问题,我建议使用Task.Run
启动后台任务。 Task.Run
比任务构造函数和Start
容易出错。
private async void Form1_Load(object sender, EventArgs e)
{
while (true)
{
int c = await Task.Run(() => check());
label7.Text = c.ToString();
}
}
或者,如果您想在后台代码中进行无限循环,则可以使用IProgress<T>
向UI线程报告进度:
private Task CheckForever(IProgress<int> progress)
{
while (true)
{
var c = check();
progress?.Report(c);
}
}
private async void Form1_Load(object sender, EventArgs e)
{
var progress = new Progress<int>(c => label7.Text = c.ToString());
await CheckForever(progress);
}
请注意,Task.Run
代码始终比BackgroundWorker
代码更整洁,易于维护并且类型安全。