好,
这里似乎有很多关于Thread.Abort()是多么糟糕的讨论,以及如何通过在循环中添加退出检查来解决在代码中使用Thread.Abort()的问题。
这假设您以一种足够精细的方式控制工作的分区方式。
但我该如何做以下事项:
启动工作线程以执行某些操作,同时保持UI响应。对于所有意图和目的,工作线程的代码如下所示:
public override void Run()
{
try
{
_dataTable = ExecuteSingleGinormousSqlQuery();
} finally
{
// close the connection if it was left open.
}
}
有“取消”按钮,以便用户可以在等待时感到厌烦。
与Thread.Abort()相比,似乎没有任何其他方法。真的吗?此外,在经验测试中,甚至看起来Thread.Abort()实际上都不会杀死线程,直到进行查询的调用,例如,
new SqlDataAdapter(cmd).Fill( ds );
首先回归,因此显着否定了它的实用性。
有解决方法吗?最佳做法?
答案 0 :(得分:2)
SqlCommand对象有一个Cancel()方法,您可以从另一个线程调用该方法以尝试取消正在运行的SQL查询。它不能保证成功,并且将取决于数据库,驱动程序和运行的实际查询,但您可能会发现它可以满足您的需求。
答案 1 :(得分:1)
你是对的,它不会立即中止一个忙于互操作的线程,这可能就是为什么它在数据库调用完成之后才会停止。 (见http://www.devx.com/codemag/Article/17442/0/page/4)
我想你可以使调用异步(参见http://www.devx.com/dotnet/Article/26747),但这意味着你不必中止线程。呼叫在后台继续,并且不会在数据库端中止。您也可以只使用同步调用并让线程完成,忽略其结果。另一个问题是,如果你想要异步,就不能使用简单的Fill方法来完成工作。
答案 2 :(得分:1)
我会终止查询或与数据库的连接。它可以通过简单的命令或过程调用在大多数服务器上完成。
您可以轻松地在发出以下命令的mysql中终止查询:
KILL QUERY <query_id>
KILL <unit of work id>
答案 3 :(得分:0)
你是工程师。没有人会因使用Abort ()
而让你入狱。
所有危险和/或弃用的结构都有特定的情况,可能是必要的,有时是必要的。这可能是一个这样的情况。掌握任何技能都是了解规则并知道何时打破它们。
但......它很大但是......最大的问题是:当`ExecuteSingleGinormousSqlQuery()'本身被中止时会发生什么?它会使客户端,服务器或数据库处于搞砸状态吗?你确定你知道会发生什么吗?您是否可以访问所有源代码?即使你这样做,你是否已经过了每一行以确保它是安全的?
Thread.Abort ()
的问题在于,任何地方都可能发生中止,我们知道CLR中存在可能使看似安全的代码行为异常的错误。
答案 4 :(得分:0)
我同意拉里的观点。只要您非常确定SQL查询不会搞砸数据库并且它看起来不会导致应用程序中的其他地方出现问题,这可能是Abort的“可接受”用途。
但是,请记住,即使您终止SQL,如果它是进行更新或删除的SQL,它仍然需要一段时间来回滚更改,并且在点击取消时不会立即释放数据库表。此外,您可能更愿意专注于优化数据库,而不是优化查询,添加索引等,以使Ginormous查询不会像显然那样长时间运行。
答案 5 :(得分:0)
另一个选择是在后台线程中执行长时间运行的操作,而不是在新进程中执行它。
有两个缺点:
进程的性能损失比线程高几个数量级。无论是启动时间还是内存开销。然而,在您的用户界面场景中,新后台进程的启动时间应该可以忽略不计,可以“眨眼间”进行测量。
您需要使用某种形式的进程间通信方法将结果返回到主程序,这通常比在线程之间共享内存更复杂。
进程与线程的好处是可以很好地理解杀死进程的语义,并且几乎可以保证进程将立即终止并且资源不会泄露。
和平
答案 6 :(得分:0)
如果您不介意重构代码,可以使用SqlCommand.BeginExecuteReader
方法或其他异步变体之一。