【问题标题】:Can I get rid of this horrible blocking code?我可以摆脱这个可怕的阻塞代码吗?
【发布时间】:2014-04-16 01:59:00
【问题描述】:

我需要一些帮助,在 web api 服务调用中,我需要调用 dll 中异步执行的函数,然后在回调函数中给出响应。现在通常这会很好,但现在使用 web api 的想法是执行命令然后返回响应。

以下是我当前有效的代码,但我认为它的代码很糟糕,它是你不想做的一切。特别是在 Web 服务器上,当此代码将为每个请求运行时。

[HttpGet]
    public HttpResponseMessage Off(string id)
    {
        APNLink.Link link = LinkProvider.getDeviceLink(id, User.Identity.Name);

        if (link.LinkConnectionStatus == APNLink.ConnectionStatus.Connected)
        {
            link.RelayCommand(APNLink.RelayNumber.Relay1, APNLink.RelayCommand.OFF, test);
            BlockForResponse();
            var msg = Request.CreateResponse(HttpStatusCode.OK);
            return msg;
        }
        else
        {
            if (link.Connect())
            {
                var status = link.LinkConnectionStatus;
                int timeout = 0;
                while (status != APNLink.ConnectionStatus.Connected)
                {
                    Thread.Sleep(500);
                    status = link.LinkConnectionStatus;
                    if (status == APNLink.ConnectionStatus.Connected)
                    {
                        break;
                    }                        
                    if (timeout++ > 16)
                    {
                        var msg1 = Request.CreateResponse(HttpStatusCode.RequestTimeout);
                        return msg1;
                    }
                }
                link.RelayCommand(APNLink.RelayNumber.Relay1, APNLink.RelayCommand.OFF, test);
                BlockForResponse();
                var msg = Request.CreateResponse(HttpStatusCode.OK);
                return msg;
            }
            else
            {
                var msg2 = Request.CreateResponse(HttpStatusCode.BadRequest);
                return msg2;
            }
        }

    }

    bool flag = false;

    public void test(bool var)
    {
    flag = true;
    }

     private static bool BlockForResponse()
    {
        int count = 0;
        while (!flag)
        {
            Thread.Sleep(500);
            if (count > 10)
            {
                //timeout
                return false;
            }
        }
        return true;
    }

现在的问题是我必须在等待 dll 时阻塞,连接要连接,然后我才能执行命令。一旦我执行了命令。然后我必须再次阻止响应。

另一个方面是,我真的可以阻塞在 asp.net 线程上吗?确定不是每个请求都在自己的线程上处理吗?

有什么方法可以让这段代码更整洁,最重要的是更高效?

【问题讨论】:

  • 关于改进代码的问题应该在codereview.stackexchange.com
  • 您的 api 是否提供任何异步版本的 RelayCommand,即 BeginRelayCommand
  • 返回签名必须更改为Task<HttpResponseMessage>stackoverflow.com/questions/14068515/…
  • @NedStoyanov api 是异步的,它只是在完成后调用回调。但遗憾的是,它只提供了示例中的内容。但是,如果有什么会产生很大的不同,我可以要求他们将该功能添加到 dll 中
  • 我的错,我是个白痴。您可以使用TaskCompletionSource 请参阅下面@Noseratio 的回复

标签: c# multithreading asynchronous task-parallel-library blocking


【解决方案1】:

回答问题:

在 web api 服务调用中,我需要调用 dll 中的函数 异步执行,然后在回调中给出响应 功能。

IMO,最好的方法是使您的控制器方法异步并使用TaskCompletionSource 包装您的 DLL 的回调。一些不错的附加读物:

代码可能如下所示:

[HttpGet]
public async Task<HttpResponseMessage> Off(string id)
{
    APNLink.Link link = LinkProvider.getDeviceLink(id, User.Identity.Name);

    if (link.LinkConnectionStatus == APNLink.ConnectionStatus.Connected)
    {
        var tcs = new TaskCompletionSource<object>();

        CallbackType test = delegate {           
           tcs.SetResult(null);
        };

        link.RelayCommand(
            APNLink.RelayNumber.Relay1, 
            APNLink.RelayCommand.OFF,
            test);

        // BlockForResponse();
        await tcs.Task; // non-blocking

        var msg = Request.CreateResponse(HttpStatusCode.OK);
        return msg;
    }

    // ...
}

【讨论】:

  • 忙于阅读您提供的链接。他们都是伟大的。正是我正在寻找的,因为我对 dll 的调用可能需要 10 秒才能执行。所以我绝对认为我需要使用异步方法。
  • @Zapnologica,请务必阅读some other links,尤其是about how AspNetSynchronizationContext works
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-08
  • 2011-03-24
相关资源
最近更新 更多