Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/mercurial/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何将异步调用转换为C中的同步调用#_C#_Multithreading_Asynchronous - Fatal编程技术网

C# 如何将异步调用转换为C中的同步调用#

C# 如何将异步调用转换为C中的同步调用#,c#,multithreading,asynchronous,C#,Multithreading,Asynchronous,我是C#的新手,我将开发一个使用第三方网络库发送请求的小程序 假设队列qTasks中存储了一些请求(只是简单的字符串),它将按照提交的顺序逐个处理这些请求,队列可以在执行过程中更新,只要返回错误,就应该停止队列 我可以使用for循环逐个调用数组中的send-request命令,但不幸的是,sendrequest命令是一个异步方法,带有callbackOnStageChanged,当状态为“完成”时,我需要在发送下一个请求之前检查结果 我现在使用以下方法来处理它: 在主UI线程中 // Put t

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

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

我可以使用for循环逐个调用数组中的send-request命令,但不幸的是,
sendrequest
命令是一个异步方法,带有callback
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)));
    }
}
此方法将发送请求,然后等待状态“完成”,然后返回结果

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

while (!requestDone);
这样它就不会继续执行
nextRequest
,直到
requestDone
。但在这种情况下,UI将被阻止


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

您将遇到的困难是您有相互冲突的愿望。一方面,您希望避免阻塞UI线程。另一方面,您不希望异步运行,因此将阻塞UI线程

您必须选择一个,并且绝对没有理由继续同步地做事情(特别是在阻塞UI线程的情况下)。如果你那样做很痛,不要那样做

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

private async void StartProcessing_Click(object sender, EventArgs e)
{
  await Task.Run(() => StartProcessing());
}
在这里,您已经开始处理,并且UI线程没有被占用

接下来的事情是,你是对的,让事件以这种循环的方式运行是愚蠢的。事件是通知某人状态已更改,其目标不是管理队列策略。队列应该管理队列策略(或者,如果您不想将其抽象出来,则使用处理请求的方法)

那你怎么做呢?您已经说过SendRequest将会话对象交还给调用者。调用者可能是编排队列策略并决定是否再次调用SendRequest的人

让调用方检查会话对象的有效性,并根据该有效性决定是否继续


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

您能举个例子说明SendRequest方法正在处理什么吗?递归是最好的方法。但是,根据逻辑,我们可以更改其编写方式。SendRequest方法由库提供。事实上,这是FiddlerCore的SendRequest方法,所需的头和requestBodyBytes是从队列中的数据生成的。如果
SendRequest
返回什么?它是否返回
任务
?但是,即使您确实使其同步,您也知道在UI线程上执行此操作将冻结UI?SendRequest返回会话对象,但我不需要此对象,因为它也可以在OnStageChangeHandler中作为输入参数使用。正如我在文章中提到的,我找到了一些使用while循环的方法,如果继续检查控制标志,UI将被冻结。所以,我想知道是否有其他更好的方法不会阻塞UI线程。我只是想看看它是否可以简化程序流程,使其看起来像一个同步调用。刚刚从msdn了解到,有一个WaitHandle用于发送信号,它可以使用WaitHandle来等待信号,而不是在控制标志上使用while循环,从而在UI线程上引入阻塞。我发现了一些示例,但都是用于在后台线程中等待的,我只是想知道它是否可以用于在UI线程中等待?i、 e.sendRequest之后,UI线程启动WaitOne,OnStageChangeHandler将在“完成”后设置信号。这样会更好吗?也许我以后可以试试。谢谢克里斯的建议。实际上,发送请求过程可以由UI按钮或计时器事件触发。应用程序中有其他进程同时运行,它们将在某个特定事件(例如,计算过程完成后)向请求队列提交请求。此外,用户还可以直接在UI中添加请求,这就是为什么我不想在发送请求时阻止UI。然后,发送请求流程将在预定义的时间段内或通过在UI中单击按钮触发的方式在队列中提交这些请求。SendRequestAndWait方法听起来就像我正在寻找的方法。但我不确定SendRequestAndWait方法是否真的会等到“完成”,因为它也有OnStageChange的回调,似乎它仍然使用回调方法通知调用方,但帮助文件没有关于它的详细信息。也许我以后会试试。非常感谢。刚刚测试过,SendRequestAndWait真的很有效。虽然它仍在使用回调通知调用者,但它会等到状态“完成”。我已经使用调试器进行了检查,它将在执行下一条语句之前完成状态为“Done”的OnStageChangeHandler。谢谢
private async void StartProcessing_Click(object sender, EventArgs e)
{
  await Task.Run(() => StartProcessing());
}