繁体   English   中英

如何隐藏异步调用以在C#中用作同步调用

[英]How to covert async call to work as sync call in C#

我是C#的新手,我将使用第三方网络库开发一个小程序来发送请求。

假设队列qTasks存储了一些请求(只是简单的字符串),它将按照提交的顺序逐个处理这些请求,可以在执行期间更新队列,并且只要返回错误,就应该停止该队列。

我只能使用for循环在数组中一个接一个地调用send request命令,但是不幸的是sendrequest命令是一个带有回调OnStageChanged的异步方法,并且当状态为“时,我需要检查结果,然后发送下一个请求完成”。

我现在使用以下方法来处理它:

在主UI线程中,

// Put those request text in a queue names qTasks, then call a goNextTask() to process the request one by one.
// The queue can be updated by the UI thread at anytime, goNextTask will be called periodically to handle those pending request in the queue.

private void goNextTask(bool lastSuccess = true)
{
    if (lastSuccess) 
    {
        if (qTasks.Count > 0) 
        {
            // continue to next request
            string requestText = qTasks.Dequeue();
            SendRequest(requestText, OnStageChangeHandler);
        } else {
            // Report for all request sent successfully
        }
    } else {
        // stop and show error
    }
}

每当阶段更改时,库都将调用回调方法OnStageChangeHandler ,并且完成时其状态将为“完成”。

private void OnStageChangeHandler(object sender, StageChangeEventArgs e)
{
    if (e.newState == SessionStates.Done)
    {
        // check result here
        bool success = <...> 

        // then call the goNextTask in UI thread with the result of current request.
        Application.Current.Dispatcher.BeginInvoke(
           System.Windows.Threading.DispatcherPriority.Normal,
          (Action)(() => goNextTask(success)));
    }
}

尽管它现在可以正常工作,但我认为它有点愚蠢,因为它具有一定的递归流程(A-> B-> A-> B-> ....)。

我了解到MS已改进了Web请求处理,因此它可以在同步模式下工作。

我想知道是否可以有一个包装器来使上述异步调用作为同步调用工作,以便可以像这样的循环那样在简单的流程中完成:

while (qTaks.Count > 0) 
{
    if (!sendAndWaitReturn(qTasks.Dequeue())) {
        // Report error and quit
    }
}
// all tasks completed

sendAndWaitReturn方法将发送请求,然后等待状态“完成”,然后返回结果。

我发现了一些示例,该示例可能使用控制标志来指示当前请求的状态,并且回调函数将更新此控制标志,而UI线程将使用while循环在此标志上循环:

while (!requestDone);

这样它就不会继续到nextRequest直到requestDone为止。 但是在这种情况下,UI将被阻止。

有没有更好的方法可以将异步调用转换为同步调用而不阻塞UI线程?

您将遇到的困难是您有相互矛盾的欲望。 一方面,您要避免阻塞UI线程。 另一方面,您不想异步运行事物,因此将阻塞UI线程。

您将不得不选择一个,并且绝对没有理由继续进行同步处理(尤其是考虑到阻塞UI线程)。 如果这样做时很痛, 请不要这样做。

您尚未指定,但我猜您正在从按钮单击事件开始此处理。 使该click事件调用的方法异步。 例如:

private async void StartProcessing_Click(object sender, EventArgs e)
{
  await Task.Run(() => StartProcessing());
}

在那里,您已经开始处理,并且UI线程没有被占用。

接下来的事情是,您是对的,让事件以周期性的方式执行是很愚蠢的。 该事件是为了通知某人状态已更改,其目的不是管理队列策略。 队列应该管理队列策略(或者,如果您不希望抽象出来,请使用处理请求方法 )。

那你该怎么做呢? 好吧,您已经说过SendRequest将会话对象移交给调用者。 调用者大概是协调队列策略并确定是否再次调用SendRequest的那个。

让调用者检查会话对象的有效性,然后根据该值决定是否继续进行。

另外,我不熟悉该特定库,但是简要浏览一下文档,看起来好像还有一个具有相同签名的SendRequestAndWait()方法,这听起来可能会更好地满足您的需求。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM