在我的C#7.0代码中,我喜欢使用Thread
类型的旧学校线程做一些工作。在这个Thread中,我需要使用一些异步方法。调用这些方法的最佳方法是什么?
编写线程函数async
没有任何意义。
this._networkListenerThread = new Thread(/* async here is not an option */() =>
{
while (!this._listenerCancellation.IsCancellationRequested)
{
try
{
// This does not compile
var packetBuffer = await this._commProxy.ReadAsync();
doSomethingMore();
}
}
}
如果我们向下调用堆栈,最后会有这个调用:
// _socket is of type Android.Bluetooth.BluetoothSocket
// .InputStream of type System.IO.Stream
// ReadAsync only returns when data arrived on the stream
// or throws an exception when the connection is lost
var receivedBytes = await this._socket.InputStream.ReadAsync(buffer, 0, buffer.Length);
对于那些想知道我为什么要使用Thread而不是Task的人:我想给它一个有意义的名称来增强调试。我找不到命名任务的方法。除此之外,这个Thread几乎和应用程序运行一样长,因此Thread对我来说很有意义。
答案 0 :(得分:2)
这个Thread几乎和应用程序一样运行
不,它没有。因为它所做的工作是异步的。线程运行的时间足以检查取消令牌的状态,触发ReadAsync
(异步,基本上会立即返回),然后完成。线程消失了,它没有更多的工作要做。这就是异步操作的整个想法;异步意味着操作几乎立即返回其调用者,并且在将控制权返回给调用者之后执行所做的任何有意义的工作(在这种情况下,因为这是该方法的顶级方法)线程,返回控制返回意味着线程已完成执行并被拆除)。
因此,创建一个新线程只是为了让它检查一个布尔值而启动一些将会自行运行的操作。这并不是说您应该使用不同的方式来获取新线程(例如使用Task.Run
),而是您不应该使用任何都可以让新线程完成工作,因为你没有任何长时间运行的CPU绑定工作要做。你已经将已经异步的长时间运行(非CPU绑定)工作,所以你可以直接从想要开始这项工作的任何线程中调用该方法,并拥有它做得很好。
如果您只想拥有一些可以在异步操作的逻辑调用上下文中共享的值,那么当然有工具可以实现这一点,例如AsyncLocal
。创建一个新线程不会完成这一点,因为当你完成启动异步操作时,你的线程已经死了,不管怎样,继续将在其他一些线程中运行。