V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Sponsored by
LinkedIn
不坐班的神仙工作 · 去任何你想去的地方远程,赚一线城市的工资
2000 个不用出门 Social 的全球远程工作,帮助 V2EX 的小伙伴开启全新的工作方式。
Promoted by LinkedIn
qtoq126
V2EX  ›  程序员

这个异步操作应该怎么写?

  •  1
     
  •   qtoq126 · 134 天前 · 1331 次点击
    这是一个创建于 134 天前的主题,其中的信息可能已经有所发展或是发生改变。
    1. c#/.net core webapi
    2. 这是一个 webAPI 的某个接口方法
    3. (步骤 1 )返回的是传给前端的 json 数据
    4. 在传递给前端数据后(步骤 2 ),还需要用这个数据去进行一个特别耗时的计算(步骤 3 )
    5. 现在我知道的是需要用异步去写步骤 2 ,但是如果加 await ,会一直等待他返回结果才会 return ,失去了 4 说的目的;但是如果不用 await ,方法直接 return 了,这个耗时操作方法就一直不会调用,好像也不行。
    6. 想请教下无所不知的 v 站大神们,感谢了

    为什么编辑不能上传图了,附上图链接

    第 1 条附言  ·  134 天前
    第 2 条附言  ·  134 天前
    上图地址: https://i.postimg.cc/kgcxk9nt/Wechat-IMG460.png
    发了贴就不能编辑也是醉了
    21 条回复    2022-05-20 12:00:42 +08:00
    DOLLOR
        1
    DOLLOR  
       134 天前
    拆接口。
    前端拿到 json 后,再次用那个 json 请求另一个接口来执行你那个“特别耗时的计算”,等待这个“特别耗时的计算”的同时,前端可以用这个 json 做其他的事情。
    Buges
        2
    Buges  
       134 天前 via Android
    你的意思是接口返回的数据不需要等待计算完成,计算的结果不需要返回给前端?
    那直接 spawn task 就好了。
    qtoq126
        3
    qtoq126  
    OP
       134 天前
    @Buges 耗时的计算方法的返回结果不需要马上返回给前端,当他再去自己调用结果的时候,再给他
    ration
        4
    ration  
       134 天前 via Android
    1.后面的处理另开一个线程
    2.使用消息队列
    qtoq126
        5
    qtoq126  
    OP
       134 天前
    @DOLLOR 拆接口确实是个好方法,只是当拿到第一段 json 然后又马上进行二次请求的时候,前端页面是不是就会暂时卡死?我是希望前端拿到一段 json 后就可以开始展示页面了,用户该干嘛干嘛,然后我后台还在继续算,算完的结果也没必要马上通知给前端,而是当他再度调用到需要这个结果的功能的时候再返回给他
    wunonglin
        6
    wunonglin  
       134 天前
    DOLLOR
        7
    DOLLOR  
       134 天前
    @qtoq126 前端只要拿到第一次请求的 json 就可以开始渲染了,第二次请求是不会阻塞渲染的。
    qtoq126
        8
    qtoq126  
    OP
       134 天前
    @DOLLOR 相当于用户可以任意操作,前端只是在后台默默请求?
    qtoq126
        9
    qtoq126  
    OP
       134 天前
    @wunonglin ts 代码看不懂哇
    DOLLOR
        10
    DOLLOR  
       134 天前
    @qtoq126 对的,这本来就是异步请求的初衷。
    Buges
        11
    Buges  
       134 天前 via Android
    @qtoq126 那就 spawn 到后台执行的同时返回一个 task id ,前端等待一段时间再用这个 id 请求第二个接口结果,如果尚未完成返回 pending 让前端等待一段时间再次请求。注意第二个接口只返回状态和结果而不要调用执行。
    不单单拆接口,所有的接口处理函数中都不要同步等待结果维持连接。你想想你等待的时候连接超时了、中断了,或者用户刷新了重新发送。
    Buges
        12
    Buges  
       134 天前 via Android
    所有接口都应该不要阻塞,尽快返回。前端无论如何都不应做“耗时”的请求,即使在后台。
    qtoq126
        13
    qtoq126  
    OP
       133 天前
    @ration 重开一个线程的话,当我使用 return 返回第一段 json 后,主线程会不会就已经结束了啊?如果主线程已经结束了的话,Task.Run()运行的耗时函数可能还没拿到结果
    qtoq126
        14
    qtoq126  
    OP
       133 天前
    @Buges 谢谢大佬点拨,你说的这个思路我能理解,就是具体到 api 的编写和异步函数的编写上面的话,就不知道怎么去做了
    Buges
        15
    Buges  
       133 天前 via Android
    @qtoq126 返回只是结束你这个请求的 handler 函数啊,主程序和后面的线程池都是一直在运行的。除非你是 php 那样用 cgi 一个请求起一个进程。
    具体实现很直接啊,第一个接口请求后 Task.Run 把耗时计算 spawn 到后台(不要 await ),并生成一个 UUID ,把这个 UUID 作为 key 和上面返回的 Task 存到一个共享的 ConcurrentDictionary 里面,并把这个 UUID 作为额外的字段加到 json 里返回给前端。
    第二个接口前端拿这个 UUID 作为参数请求,拿到后通过这个 UUID 取得上面存的 Task 并检查 Task.Status 是否已经完成,未完成就返回 pending ,完成就返回结果(和释放资源)。

    前端请求先第一个接口拿到 json 和 UUID 先渲染,然后等待一段时间在用 UUID 请求第二个接口,如果为 pending 那就等待一段时间重试直到拿到结果。
    frisktale
        16
    frisktale  
       133 天前
    如果你期望的是”执行步骤 3“且不关心返回值”,可以利用 Hangfile 库的 BackgroundJob.Enqueue 方法。
    frisktale
        17
    frisktale  
       133 天前
    不对啊,你说的第五点怎么和我印象里的不太一样。我记得,哪怕你不 await ,只要主程序不结束运行,你的异步方法还是会完整的执行下去的,只不过在异步方法的外部没法捕获异常。
    frisktale
        18
    frisktale  
       133 天前
    Feiir
        19
    Feiir  
       133 天前
    成熟的方案就是队列
    llwuuzz
        20
    llwuuzz  
       133 天前
    伪代码:_=一个返回值为 Task 的方法;
    这样就不会等待了,方法还是会执行的,也不需要用 Task.Run 之内的再封装了
    qtoq126
        21
    qtoq126  
    OP
       130 天前
    @llwuuzz 我试试你说的这种方案
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1150 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 42ms · UTC 21:47 · PVG 05:47 · LAX 14:47 · JFK 17:47
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.