我正在使用异步I/O与HID设备进行通信,并且我希望在超时时抛出一个可捕获的异常.我有以下读取方法:
public async Task<int> Read( byte[] buffer, int? size=null )
{
size = size ?? buffer.Length;
using( var cts = new CancellationTokenSource() )
{
cts.CancelAfter( 1000 );
cts.Token.Register( () => { throw new TimeoutException( "read timeout" ); }, true );
try
{
var t = stream.ReadAsync( buffer, 0, size.Value, cts.Token );
await t;
return t.Result;
}
catch( Exception ex )
{
Debug.WriteLine( "exception" );
return 0;
}
}
}
Run Code Online (Sandbox Code Playgroud)
从Token的回调抛出的异常不会被任何try/catch块捕获,我不知道为什么.我以为它会被等待,但事实并非如此.有没有办法捕获这个异常(或让它由Read()的调用者捕获)?
编辑: 所以我重新阅读msdn上的文档,它说:"委托生成的任何异常都将从此方法调用中传播出来."
我不确定"传播出这个方法调用"是什么意思,因为即使我将.Register()调用移到try块中,异常仍然没有被捕获.
这是我的情况:
private CancellationTokenSource cancellationTokenSource;
private CancellationToken cancellationToken;
public IoTHub()
{
cancellationTokenSource = new CancellationTokenSource();
cancellationToken = cancellationTokenSource.Token;
receive();
}
private void receive()
{
eventHubClient = EventHubClient.CreateFromConnectionString(connectionString, iotHubD2cEndpoint);
var d2cPartitions = eventHubClient.GetRuntimeInformation().PartitionIds;
foreach (string partition in d2cPartitions)
{
ReceiveMessagesFromDeviceAsync(partition, cancellationToken);
}
}
private async Task ReceiveMessagesFromDeviceAsync(CancellationToken ct)
{
var eventHubReceiver = eventHubClient.GetDefaultConsumerGroup().CreateReceiver(partition, DateTime.UtcNow);
while (true)
{
if(ct.IsCancellationRequested)
{
break;
}
EventData eventData = await eventHubReceiver.ReceiveAsync();
if (eventData == null) continue;
string data = Encoding.UTF8.GetString(eventData.GetBytes());
// Javascript function with Websocket
Clients.All.setMessage(data);
} …
Run Code Online (Sandbox Code Playgroud) CancellationTokenSource
有TryReset()
会员。该文档看起来如此严格,让我想知道它为什么存在。
Cancel()
它的情况下它才会起作用。那么人们为什么要费心呢TryReset
?为什么不简单地为每个异步操作创建一个全新的CancellationTokenSource
,然后在操作完成且不再需要取消后将其丢弃?CancellationTokenSource
创建一个对象是否非常昂贵?
我想用一个CancellationToken
取消的呼叫HttpClient.PostAsJsonAsync
.然而,以下设置调用PostAsJsonAsync
无限期挂起(我离开它运行数分钟).
CancellationTokenSource source = new CancellationTokenSource();
source.Cancel();
HttpClient client = new HttpClient();
try
{
var task = client.PostAsJsonAsync<MyObject>("http://server-address.com",
new MyObject(), source.Token);
task.Wait();
}
catch (Exception ex)
{
//Never gets hit.
}
Run Code Online (Sandbox Code Playgroud)
请注意,我传递一个已经取消了CancellationTokenSource
-我有同样的问题,如果我取消使用令牌Task.Delay
有短暂的延迟.
我知道我可以简单地检查是否该令牌之前已经电话取消,但即便如此,我也有同样的问题,如果令牌被短暂延迟后取消,也就是说,它不是在方法调用之前取消,但因此后不久变得它.
所以我的问题是,是什么原因造成这一点,我可以做些什么来解决什么/解决这个问题?
编辑
对于那些寻找一个变通方法,通过@Darrel米勒的回答启发,我想出了下面的扩展方法:
public static async Task<HttpResponseMessage> PostAsJsonAsync2<T>(this HttpClient client, string requestUri, T value, CancellationToken token)
{
var content = new ObjectContent(typeof(T), value, new JsonMediaTypeFormatter());
await content.LoadIntoBufferAsync();
return await client.PostAsync(requestUri, content, token);
}
Run Code Online (Sandbox Code Playgroud) c# task-parallel-library cancellationtokensource dotnet-httpclient
我正在尝试为游戏构建界面.游戏运行1分钟.该GetStop方法后60秒游戏停止.该游戏方法在游戏开始时和退出方法退出游戏.理想情况下,我想要的是当我在30秒后退出游戏时,计时器应该重置,点击"播放"按钮,计时器应该再次运行1分钟.这样下一场比赛就可以运行1分钟.如果我再次按退出按钮,则应重置计时器以进行下一场比赛.
但是,我的代码中似乎存在某个问题.每当我执行quit方法时,计时器似乎都保存在该状态.所以,如果我在30秒内退出比赛,那么下一场比赛将持续30秒.如果我在50秒内退出比赛,下一场比赛将只持续10秒.理想情况下,计时器应该重置但不会重置.
我在这里没有想法.任何人都可以提供一些建议?
private async Task GetStop(CancellationToken token)
{
await Task.Run(async () =>
{
token.ThrowIfCancellationRequested();
await Task.Delay(TimeSpan.FromSeconds(60), token);
token.ThrowIfCancellationRequested();
if (!token.IsCancellationRequested)
{
sendMessage((byte)ACMessage.AC_ESCAPE);
}
}, token);
}
public async void Play()
{
sendMessage((byte)ACMessage.AC_START_RACE);
_cts.Cancel();
if (_cts != null)
{
_cts.Dispose();
_cts = null;
}
_cts = new CancellationTokenSource();
await GetStop(_cts.Token);
}
public void Quit()
{
_cts.Cancel();
if (_cts != null)
{
_cts.Dispose();
_cts = null;
}
//
}
Run Code Online (Sandbox Code Playgroud) c# task-parallel-library cancellation cancellationtokensource
使用TPL Dataflow库,我想做这样的事情:
myActionBlock.Post(newValue, cancelAllPreviousPosts: true);
Run Code Online (Sandbox Code Playgroud)
似乎ActionBlock上的取消令牌取消了整个事情; 如果我设置了那个,我必须创建一个新的ActionBlock.是否可以使用ActionBlock进行部分取消?
尚未尝试尚未处理的帖子.如果有一些取消令牌可用于检查当前正在执行的帖子,那将是很好的.
c# task-parallel-library cancellationtokensource tpl-dataflow
当NamedPipeServer流从管道读取任何数据时,它不响应 CancellationTokenSource.Cancel()
这是为什么?
如何限制我在服务器中等待来自客户端的数据的时间?
代码重现:
static void Main(string[] args)
{
Server();
Clinet();
Console.WriteLine("press [enter] to exit");
Console.ReadLine();
}
private static async Task Server()
{
using (var cancellationTokenSource = new CancellationTokenSource(1000))
using (var server = new NamedPipeServerStream("test",
PipeDirection.InOut,
1,
PipeTransmissionMode.Byte,
PipeOptions.Asynchronous))
{
var cancellationToken = cancellationTokenSource.Token;
await server.WaitForConnectionAsync(cancellationToken);
await server.WriteAsync(new byte[]{1,2,3,4}, 0, 4, cancellationToken);
var buffer = new byte[4];
await server.ReadAsync(buffer, 0, 4, cancellationToken);
Console.WriteLine("exit server");
}
}
private static async Task Clinet()
{
using (var client = new NamedPipeClientStream(".", "test", …
Run Code Online (Sandbox Code Playgroud) 我正在阅读F#的乐趣和利润 - 异步编程.在取消工作流程下,他们有以下示例:
let testLoop = async {
for i in [1..100] do
// do something
printf "%i before.." i
// sleep a bit
do! Async.Sleep 10
printfn "..after"
}
open System
open System.Threading
// create a cancellation source
let cancellationSource = new CancellationTokenSource()
// start the task, but this time pass in a cancellation token
Async.Start (testLoop,cancellationSource.Token)
// wait a bit
Thread.Sleep(200)
// cancel after 200ms
cancellationSource.Cancel()
Run Code Online (Sandbox Code Playgroud)
他们说:
在F#中,任何嵌套的异步调用都会自动检查取消令牌!
在这种情况下,它是线:
Run Code Online (Sandbox Code Playgroud)do! Async.Sleep(10)
从输出中可以看出,此行是取消发生的位置.
但是,对我来说(VS2010,F#2.0,F#Interactive)我得到以下输出.请注意..after …
所以我有这个代码:
//CancelationToken
CancellationTokenSource src = new CancellationTokenSource();
CancellationToken ct = src.Token;
ct.Register(() => Console.WriteLine("Abbruch des Tasks"));
//Task
Task t = new Task(() =>
{
System.Threading.Thread.Sleep(1000);
if (ct.IsCancellationRequested)
{
try
{
//Throw
ct.ThrowIfCancellationRequested();
}
catch (OperationCanceledException)
{
Console.WriteLine(
"ThrowIfCancellationRequested() liefert eben eine Exception");
}
}
}, ct);
//Run Task and Cancel
t.Start();
src.CancelAfter(350);
t.Wait();
// Get Information
Console.WriteLine("Canceled: {0} . Finished: {1} . Error: {2}",
t.IsCanceled, t.IsCompleted, t.IsFaulted);
Run Code Online (Sandbox Code Playgroud)
所以在这种情况下我取消了我的任务,但我的输出最后是:"取消:假.完成:真.错误:错误"
在我看来,它应该是"取消:真实.完成:假".为什么我得到这个结果?因为我试图抓住异常?
我试过没有try-catch块,但是由于OperationCanceledException,我的程序停止了.有人能帮助我吗?
我正在尝试将HttpClient调用的默认超时设置为5秒.
我通过这样做了CancellationTokenSource
.
这是相关的代码:
var cancellationToken = new CancellationTokenSource();
cancellationToken.CancelAfter(TimeSpan.FromSeconds(5));
var result = _httpClient.SendAsync(request, cancellationToken.Token);
Run Code Online (Sandbox Code Playgroud)
按照调用代码获取"任务被取消"错误(我在.NET 4.7控制台应用程序中测试)的预期工作,但我注意到在Fiddler中请求仍然运行1分钟,直到它最终放弃:
有人可以解释这种行为吗?
我希望在触发取消时基础请求也会被取消.
_httpClient
实例化如下: new HttpClient { BaseAddress = baseAddress }
我知道有Timeout
设置,但不确定我是否应该使用它或取消令牌?我的猜测是Timeout
针对非异步/等待的情况?
c# cancellationtokensource dotnet-httpclient cancellation-token
c# ×9
.net ×1
async-await ×1
asynchronous ×1
cancellation ×1
f# ×1
named-pipes ×1
task ×1
tpl-dataflow ×1