你好,这可以在c#中找到:
如果我有一个循环说:
int x = 0;
for (int i = 0; i < 1000000; i++) {
x++;
}
完成时间超过1秒,是否可以终止代码并继续前进?
答案 0 :(得分:5)
是的,如果您在不同的线程中运行循环,则可以从其他线程中止该线程。这将有效地杀死您正在运行的代码,并且在您给出的简化示例中可以正常工作。以下代码演示了如何执行此操作:
void Main()
{
double foo = 0;
var thread = new Thread(() => foo = GetFoo());
thread.Start();
string message;
if(thread.Join(1000))
{
message = foo.ToString();
}
else
{
message = "Process took too long";
thread.Abort();
}
message.Dump();
}
public double GetFoo() {
double a = RandomProvider.Next(2, 5);
while (a == 3) { RandomProvider.Next(2, 5);}
double b = RandomProvider.Next(2, 5);
double c = b /a;
double e = RandomProvider.Next(8, 11);
while (e == 9) { RandomProvider.Next(8,11); }
double f = b / e;
return f;
}
然而,正如你可以从Eric Lippert的评论(和其他人)中看到的那样,中止一个帖子不是很优雅(a.k.a。“纯粹的邪恶”)。如果你在这个循环中发生了重要的事情,你可能会通过在循环中间强制线程中止来使数据处于不稳定状态。所以它是可能的,但是你想要使用这种方法将取决于你在循环中做了什么。
所以更好的选择是让你的循环在被告知时自愿决定退出(更新2015/11/5以使用更新的TPL类):
async void Main()
{
try
{
var cancelTokenSource = new CancellationTokenSource(TimeSpan.FromMilliseconds(1000));
var foo = await GetFooAsync(cancelTokenSource.Token);
Console.WriteLine(foo);
}
catch (OperationCanceledException e)
{
Console.WriteLine("Process took too long");
}
}
private Random RandomProvider = new Random();
public async Task<double> GetFooAsync(CancellationToken cancelToken) {
double a = RandomProvider.Next(2, 5);
while (a == 3)
{
cancelToken.ThrowIfCancellationRequested();
RandomProvider.Next(2, 5);
}
double b = RandomProvider.Next(2, 5);
double c = b /a;
double e = RandomProvider.Next(8, 11);
while (e == 9)
{
cancelToken.ThrowIfCancellationRequested();
RandomProvider.Next(8,11);
}
double f = b / e;
return f;
}
这使GetFooAsync
有机会了解它应该很快退出的事实,并确保它在放弃鬼魂之前进入稳定状态。
答案 1 :(得分:5)
如果您控制需要关闭的代码,则将逻辑写入其中,使其能够从另一个线程中干净地关闭。
如果您不控制需要关闭的代码,则有两种情况。首先,它是敌对给你并积极抵制你关闭它的企图。这是一个错误的情况。理想情况下,您应该在另一个进程中运行该代码,而不是另一个进程,并销毁该进程。一个充满敌意的线程有很多技巧可以阻止你关闭它。
其次,如果它不是敌对的并且它不能干净地关闭那么它的设计很糟糕,或者它是错误的。修理它。如果你无法修复它,请在另一个进程中运行它,就像它是敌对的一样。
你应该做的最后一件事是中止线程。线程中止是纯粹的邪恶,应该只作为最后的手段。正确的做法是设计代码,以便可以干净,快速地取消代码。
更多想法:
http://blogs.msdn.com/b/ericlippert/archive/2010/02/22/should-i-specify-a-timeout.aspx
或者,您可以使用单线程方法。将工作分解成小块,每个工作块的最后一件事就是将下一块工作排入工作队列。然后你坐在一个循环中,将工作拉出队列并执行它。要提前停止,只需清除队列即可。如果你不需要,不需要采用多线程方法。
答案 2 :(得分:1)
您可以通过简单的方式实现这一目标,而无需使用线程:
int x = 0;
int startTime = Environment.TickCount;
for (int i = 0; i < 1000000; i++)
{
x++;
int currentTime = Environment.TickCount;
if ((currentTime - startTime) > 1000)
{
break;
}
}
如果您愿意,可以将Environment.TickCount
替换为DateTime
或System.Diagnostics.Stopwatch
。
答案 3 :(得分:0)
您可以使用background worker,此类支持取消
答案 4 :(得分:0)
如果问题是循环中迭代次数多于循环内部的迭代次数,则可以请求保存循环开始时的时间,并查看每次迭代之间的差异(或者可能是%10,20) ,100)并取消,如果您想在该任务上花费的时间结束。