我有以下代码:
Thread validationThread = new Thread(DoAsyncValidationMethod);
validationThread.Start(threadParams);
bool isAborted = false;
int timeLeft = 5000;
// wait for thread terminates itself
if (!validationThread.Join(timeLeft))
{
// timeout, abort thread
validationThread.Abort();
isAborted = true;
}
换句话说,我正在做一些应该在指定的时间间隔内完成的工作(5000毫秒)。如果完成或不完成,采用的线程方法将保证代码在启动后不迟于5秒返回。
有没有办法用async / await模式完成这个?或者因为线程只是用于技巧,还有其他方法吗?
越优雅,越简单越好。 谢谢你的帮助。
答案 0 :(得分:2)
以下是我在其中一个项目中使用的一段代码。
更多信息,请查看Task.WhenAny(param Task[] task) method on MSDN。它返回完成的任务。
class SongsViewController {
var currentHeaderHeight: CGFloat = 136
func scrollViewDidScroll(_ scrollView: UIScrollView) {
//Throws error
guard let currentHeaderHeight = self.songsTable.headerView(forSection: 0)?.frame.size.height else {
print("header view has no height")
return
}
}
public func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return currentHeaderHeight
}
public func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView()
headerView.frame = CGRect(x: 0, y: 0, width: Screen.width, height: maxHeaderHeight)
return headerView
}
}
答案 1 :(得分:2)
使用CancellationTokenSource
。源是CancellationTokens
的工厂。您将此令牌传递给您希望能够以整洁的方式取消其处理的每个人。如果您要取消同一CancellationToken
中CancellationTokenSource
的所有流程,只需告诉CancellationTokenSource
向其生成的所有CancellationTokens
发送取消,从而取消所有流程从这个来源获得令牌。
好的是,CancellationTokenSource
有一个CancelAfter(some timeout)
。
这是一个很好的做法,让您的流程启动器为您提供cancelToken,这样您的流程启动器就可以决定在一次调用中取消哪些流程。
public async Task<MyResult> MyProcessAsync(CancellationToken cancellationToken, ...)
{
// do something lengthy processing, without await, regularly check if Cancellation requested
while (stillProcessing)
{
cancellationToken.ThrowIfCancellationRequested();
... // process
}
// do some processing with async-await:
await myDbContext.SaveChangesAsync(cancellationToken);
}
用法:
private async Task LengthyProcessing(...)
{
CancellationTokenSource tokenSource = new CancellationTokenSource();
tokenSource.CancelAfter(TimeSpan.FromSeconds(5));
CancellationToken myCancellationToken = tokenSource.Token
try
{
// Start one task, don't await yet:
var myTask = await MyProcessAsync(myCancellationToken, ...)
// during processing there will be regular check if cancellation requested
// meanwhile, whenever myTask has to await, I can do some processing
// I'll have to check for cancellation regularly also:
while(...)
{
myCancellationToken.ThrowIfCancellationRequested();
DoSomeProcessing();
...
}
MyResult result = await myTask;
// if here, not cancelled. can use Result:
ProcessResult(result);
}
catch (OperationCanceledException exc)
{
ProcessOperationCanceled();
}
}
请注意,只使用了一个CancelltionTokenSource。每当此来源认为应取消某些内容时,所有来自此来源的令牌的线程都会收到有关取消请求的通知。
不要通过CancellationToken.ThrowIfCancellationRequested()
使用异常处理,而应考虑使用bool CancellationToken.IsCancellationRequested
。
答案 2 :(得分:0)
您可以使用Microsoft的Reactive Framework(NuGet&#34; System.Reactive&#34;)来做到这一点。然后你可以这样做:
IObservable<bool> query =
Observable.Amb(
Observable.Timer(TimeSpan.FromSeconds(5.0)).Select(_ => false),
Observable.Start(() => DoAsyncValidationMethod()).Select(_ => true));
IDisposable subscription =
query.Subscribe(flag =>
{
/* `true` succeeded, `false` timed out */
});