簡體   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