中止 运行 长查询的线程
Abort a thread which is running a long query
我有一个调用其中一种方法的线程,现在这个方法执行的查询可能需要很长时间,可能需要 40 分钟左右才能完成,
我想给用户一个选择来取消这个操作(意思是停止线程和停止查询以释放数据库)。
我应该提到我正在使用 .net 4.5、SQL SERVER DB 和 C# 开发 WPF 应用程序。
使用 Task Parallel Library (TPL) you can use the Task Cancellation 模式。
这是 WPF
和 WinForm
中常见的 problem.But,我想使用 BackGroundWorker
。参见 Here
你应该使用backgroundworker,这正是你想要的。
Eather 从工具箱中拖放它或在后面的代码中创建它。它支持取消、报告进度、完成时通知并知道它是否 运行。
这是一个例子。
void method(){
BackgroundWorker worker = new BackgroundWorker();
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.ProgressChanged += worker_ProgressChanged;
worker.DoWork += worker_DoWork;
worker.WorkerSupportsCancellation = true;
if(!worker.IsBusy)
{
worker.RunWorkerAsync();
}
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
//do whatever needs to be done on the other thread here.
object argument = e.Argument; //if passed argument in RunWorkerAsync().
object result = new object();
e.Result = result;
//after making worker global, you can report progress like so:
worker.ReportProgress(50); //you can also pass a userState, which can be any object, to show some data already.
}
void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//you can update a progress bar in here
int progress = e.ProgressPercentage;
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//when done
}
void CancelTheTask()
{
if (worker.IsBusy)
{
//make worker global first, but then
worker.CancelAsync();
}
}
需要注意的重要事项:切勿在 DoWork
方法中使用不是在其中创建的资源。因此,将您需要的东西作为参数传递给后台工作人员。而backgroundworker创建的东西不应该设置为全局变量ether,按结果传递。
取消时,RunWorkCompleted
也会被解雇。现在对数据库的查询已经在执行,因此即使您的应用程序失去了所有资源,它仍然是 运行。
要取消它,我们需要知道您如何执行查询,就像提到的 是一种方式。 Entity Framework6也支持取消。
为此:check this when using Queryable
here is another example
或者这个 solution 没有 Entity Framework。
如果 UI 线程正在进行长时间操作,它将无法处理
UI 个请求。这也称为 无响应 。
像这样使用 ThreadPool
:
CancellationTokenSource ct;//instantiate it before ThreadPool.QueueUserWorkItem line
private void operation_Click(object sender, RoutedEventArgs e)
{
ct = new CancellationTokenSource();
ThreadPool.QueueUserWorkItem(_ =>
{
var result = LongTimeOperation();//set the operation in another thread so that the UI thread is kept responding
//use the Dispatcher to "return" to the UI thread
Dispatcher.BeginInvoke(new Action(() =>
{
//Use result for example : Label1.Text = result.ToString();
}));
});
}
要让用户可以选择取消操作,请像这样使用 CancellationTokenSource
:
private void cancel_Click(object sender, RoutedEventArgs e)
{
if (ct != null)
{
ct.Cancel();
ct= null;
}
}
注意: in LongTimeOperation
() 必须多一个 CancellationToken
类型的参数
private float LongTimeOperation(CancellationToken ct)
{
if (ct.IsCancellationRequested)
return -1;
....
....
}
这个 link 在托管线程中对 Cancellation
很有用。
当您的线程因等待查询而阻塞时,停止任何操作都是无用的。
确保查询的 SqlConnection 可从您的 UI 访问并关闭它。放弃线程,它将终止(出现错误你必须抑制)。
我有一个调用其中一种方法的线程,现在这个方法执行的查询可能需要很长时间,可能需要 40 分钟左右才能完成,
我想给用户一个选择来取消这个操作(意思是停止线程和停止查询以释放数据库)。
我应该提到我正在使用 .net 4.5、SQL SERVER DB 和 C# 开发 WPF 应用程序。
使用 Task Parallel Library (TPL) you can use the Task Cancellation 模式。
这是 WPF
和 WinForm
中常见的 problem.But,我想使用 BackGroundWorker
。参见 Here
你应该使用backgroundworker,这正是你想要的。
Eather 从工具箱中拖放它或在后面的代码中创建它。它支持取消、报告进度、完成时通知并知道它是否 运行。
这是一个例子。
void method(){
BackgroundWorker worker = new BackgroundWorker();
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.ProgressChanged += worker_ProgressChanged;
worker.DoWork += worker_DoWork;
worker.WorkerSupportsCancellation = true;
if(!worker.IsBusy)
{
worker.RunWorkerAsync();
}
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
//do whatever needs to be done on the other thread here.
object argument = e.Argument; //if passed argument in RunWorkerAsync().
object result = new object();
e.Result = result;
//after making worker global, you can report progress like so:
worker.ReportProgress(50); //you can also pass a userState, which can be any object, to show some data already.
}
void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//you can update a progress bar in here
int progress = e.ProgressPercentage;
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//when done
}
void CancelTheTask()
{
if (worker.IsBusy)
{
//make worker global first, but then
worker.CancelAsync();
}
}
需要注意的重要事项:切勿在 DoWork
方法中使用不是在其中创建的资源。因此,将您需要的东西作为参数传递给后台工作人员。而backgroundworker创建的东西不应该设置为全局变量ether,按结果传递。
取消时,RunWorkCompleted
也会被解雇。现在对数据库的查询已经在执行,因此即使您的应用程序失去了所有资源,它仍然是 运行。
要取消它,我们需要知道您如何执行查询,就像提到的
为此:check this when using Queryable
here is another example
或者这个 solution 没有 Entity Framework。
如果 UI 线程正在进行长时间操作,它将无法处理
UI 个请求。这也称为 无响应 。
像这样使用 ThreadPool
:
CancellationTokenSource ct;//instantiate it before ThreadPool.QueueUserWorkItem line
private void operation_Click(object sender, RoutedEventArgs e)
{
ct = new CancellationTokenSource();
ThreadPool.QueueUserWorkItem(_ =>
{
var result = LongTimeOperation();//set the operation in another thread so that the UI thread is kept responding
//use the Dispatcher to "return" to the UI thread
Dispatcher.BeginInvoke(new Action(() =>
{
//Use result for example : Label1.Text = result.ToString();
}));
});
}
要让用户可以选择取消操作,请像这样使用 CancellationTokenSource
:
private void cancel_Click(object sender, RoutedEventArgs e)
{
if (ct != null)
{
ct.Cancel();
ct= null;
}
}
注意: in LongTimeOperation
() 必须多一个 CancellationToken
private float LongTimeOperation(CancellationToken ct)
{
if (ct.IsCancellationRequested)
return -1;
....
....
}
这个 link 在托管线程中对 Cancellation
很有用。
当您的线程因等待查询而阻塞时,停止任何操作都是无用的。
确保查询的 SqlConnection 可从您的 UI 访问并关闭它。放弃线程,它将终止(出现错误你必须抑制)。