我有一个从队列中读取的阻塞操作,但可能需要超时。我可以轻松地将其转换为“异步”操作:
public async Task<IMessage> ReceiveAsync(CancellationToken cancellationToken)
{
return await Task.Run(() =>
{
while (true)
{
cancellationToken.ThrowIfCancellationRequested();
// Try receiving for one second
IMessage message = consumer.Receive(TimeSpan.FromSeconds(1));
if (message != null)
{
return message;
}
}
}, cancellationToken).ConfigureAwait(false);
}
由于您可以泄漏资源,因此中止线程通常被认为是不好的做法,因此超时似乎是干净地停止线程的唯一方法。所以我有三个问题:
编辑:所以我可能已经使用Thread.Interrupt()
找到了部分答案,然后处理ThreadInterruptedException
。这基本上是内核级软件中断,并且尽可能接近“立即”吗?以下是更好的处理方法吗?
public async Task<IMessage> ReceiveAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var completionSource = new TaskCompletionSource<IMessage>();
var receiverThread = new Thread(() =>
{
try
{
completionSource.SetResult(consumer.Receive());
}
catch (ThreadInterruptedException)
{
completionSource.SetCanceled();
}
catch (Exception ex)
{
completionSource.SetException(ex);
}
});
cancellationToken.Register(receiverThread.Interrupt);
receiverThread.Name = "Queue Receive";
receiverThread.Start();
return await completionSource.Task.ConfigureAwait(false);
}
答案 0 :(得分:1)
async
API的库(好的)从下到上。它们通常不会使用线程包装阻塞(同步)操作,使它们看起来是异步的。他们使用TaskCompletionSource
创建真正的async
方法。Queue
没有Receive
方法)你可能应该使用真正的async
TPL Dataflow
{/ 1}}等BufferBlock
数据结构
醇>
关于您的特定代码示例。
你在整个操作过程中都是一个线程(那个async over sync),这个代价很高。您可以尝试快速使用,然后异步等待超时结束,或者CancellationToken
被取消。
使用Task.Run
的另一个线程也没有意义。您可以简单地将async
lambda作为ReceiveAsync
的内容:
public async Task<IMessage> ReceiveAsync(CancellationToken cancellationToken)
{
while (true)
{
cancellationToken.ThrowIfCancellationRequested();
// Try receiving for one second
IMessage message;
if (!consumer.TryReceive(out message))
{
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
}
if (message != null)
{
return message;
}
}
}
如果您的队列实施IDisposable
,则取消Dispose
时,另一个(更严厉)选项就是在其上调用CancellationToken
。 Here's how