首页 新闻 会员 周边 捐助

.Net Task 异步 报错: A task was canceled.

0
悬赏园豆:40 [已解决问题] 解决于 2018-02-01 09:46

需求是这样的:

  1. 客户端a 向服务器发起一次请求 服务器hold请求 不返回
  2. 等待客户端b 发起请求后, 这个时候 a 的请求就可以返回了

这个是我这边大致的实现代码

然后报错

有没有大神知道为什么会这样, 有没有别的办法达到这个效果吗

把GetString方法改成这样好像也能达到预期, 但是不知道有没有Bug会不会很耗性能, 其实我更想知道的是前面为什么会报错, 以及解决办法

   public async Task<string> GetString()
   {
        while (!source.IsCancellationRequested)
        {
             await Task.Delay(1 * 1000);
        }
        //await Task.Delay(10 * 1000, source.Token);
        return "";
  }
Mirck的主页 Mirck | 初学一级 | 园豆:114
提问于:2018-01-25 21:40
< >
分享
最佳答案
0

Task.Delay中传CancellationToken就是会抛异常,要想不抛异常用Task.WhenAny和TaskCompletionSource的组合即可。

    static TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();

    string GetB()
    {
        tcs.SetCanceled();
        return "";
    }

    async Task<string> GetString()
    {
        await Task.WhenAny(Task.Delay(3000), tcs.Task);
        return "";
    }
收获园豆:30
天方 | 大侠五级 |园豆:5407 | 2018-01-25 22:30

厉害了, 这个就是我想要的

Mirck | 园豆:114 (初学一级) | 2018-01-25 23:14
其他回答(3)
-1

2次请求不是同一个Controller实例

dudu | 园豆:30939 (高人七级) | 2018-01-25 22:09

CancellationTokenSource source 是一个静态对象的

支持(0) 反对(0) Mirck | 园豆:114 (初学一级) | 2018-01-25 22:14
0

ManualResetEvent

AutoResetEvent

Monitor

收获园豆:5
梦里的畅泳 | 园豆:159 (初学一级) | 2018-01-25 22:30
-1

不建议你这样做,如果在你的场景下b不调用你那服务,那服务最后会因为资源耗尽跪掉

应该是a发消息过来然后就返回,b后面一旦给你了相关联的请求后再回调a

收获园豆:5
Daniel Cai | 园豆:10424 (专家六级) | 2018-01-25 22:30

其实我也不想这么弄的, 客户端b 其实也是一台服务器
当收到客户端a 的请求后, 服务器需要向b 发送一个请求, 然后 b 收到请求后, 在异步向我们服务器发送一个请求, 当收到b 的请求后, 我们服务器需要把b 的返回值返回给 客户端 a

这个主要是服务器b 就是一个奇葩, 他们不能同步的返回消息,
然后客户端 a 也是一个奇葩, 两分钟请求一次我们不能主动通知他, 又必须马上获得结果

支持(0) 反对(0) Mirck | 园豆:114 (初学一级) | 2018-01-25 23:04

@Mirck: 真心建议你们这个玩意再考虑下,不然到时候出了问题谁背锅?

如果你非要按照你的逻辑来掰的话是有点麻烦的,你需要一个有key为包含发送给b的请求标识,value为类似ManualResetEvent(太重)或者ManualResetEventSlim的玩意来进行控制。

如果你的服务是个集群的话就更麻烦点,需要找个缓存啥的做个分布式锁(确保在收到b的响应式请求前处理a请求的继续阻塞住)

支持(0) 反对(0) Daniel Cai | 园豆:10424 (专家六级) | 2018-01-25 23:16
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册