簡體   English   中英

C#異步等待池

[英]C# async await for pooling

我需要每2秒對某個端點執行一些WebRequest。 我嘗試使用Timer來完成此操作,問題是每次對回調函數的調用都在創建一個不同的線程,並且我遇到了一些並發問題。 因此,我決定更改實現,當時我正在考慮使用內部睡眠時間為兩秒鍾的后台工作程序或使用異步等待,但是我看不到使用異步等待的好處。 有什么建議嗎? 謝謝。

這是我將重新實現的代碼。

private void InitTimer()
{
    TimerCallback callback = TimerCallbackFunction;
    m_timer = new Timer(callback, null, 0, m_interval);
}

private void TimerCallbackFunction(Object info)
{
    Thread.CurrentThread.Name = "Requester thread ";
    m_object = GetMyObject();
}

public MyObject GetMyObject()
{
    MyObject myobject = new MyObject();

    try
    {
        MemoryStream responseInMemory = CreateWebRequest(m_host, ENDPOINT);
        XmlSerializer xmlSerializer = new XmlSerializer(typeof(MyObject));
        myObject = (MyObject) xmlSerializer.Deserialize(responseInMemory);
    }
    catch (InvalidOperationException ex)
    {
        m_logger.WriteError("Error getting MyObject: ", ex);
        throw new XmlException();
    }
    return myObject;
}

private MemoryStream CreateWebRequest(string host, string endpoint)
{
    WebRequest request = WebRequest.Create(host + endpoint);
    using (var response = request.GetResponse())
    {
        return (MemoryStream) response.GetResponseStream();
    }
}

編輯:我已閱讀此SO線程Async / await與BackgroundWorker

異步等待也是並發的。 如果您有並發問題,並且您希望應用程序只有一個線程,則應避免使用異步等待。

但是,執行WebRequest的最佳方法是使用異步等待,它不會阻塞主UI線程。

使用波紋管方法,它不會阻塞任何東西,Microsoft建議。 https://msdn.microsoft.com/zh-CN/library/86wf6409(v=vs.110).aspx

private async  Task<MemoryStream> CreateWebRequest(string host, string endpoint)
{
    WebRequest request = WebRequest.Create(host + endpoint);
    using (var response = await request.GetResponseAsync())
    {
        return (MemoryStream)response.GetResponseStream();
    }
}

您沒有提到並發問題。 該請求可能花費了很長時間,以至於下一個請求開始之前的請求結束。 也可能是當讀者訪問它時,回調替換了my_Object的值。

您可以使用Task.Delay輕松地每隔X秒異步且無阻塞地發出請求,例如:

ConcurrentQueue<MyObject> m_Responses=new ConcurrentQueue<MyObject>();
public async Task MyPollMethod(int interval)
{
    while(...)
    {
        var result=await SomeAsyncCall();
        m_Responses.Enqueue(result);
        await Task.Delay(interval);
    }
}

最后一個結束后X秒鍾將導致輪詢呼叫。

它還通過將結果存儲在並發隊列中而不是替換舊值(可能是在其他人正在讀取int時)來避免並發問題。

MyObject的使用者將調用Dequeue來按其接收順序檢索MyObject實例。

您也可以使用ConcurrentQueue來修復當前代碼:

private void TimerCallbackFunction(Object info)
{
    Thread.CurrentThread.Name = "Requester thread ";
    var result=GetMyObject(); 
    m_Responses.Enqueue(result);
}

要么

private async void TimerCallbackFunction(Object info)
{
    Thread.CurrentThread.Name = "Requester thread ";
    var result=await GetMyObjectAsync(); 
    m_Responses.Enqueue(result);
}

如果您想將GetObject方法更改為異步工作。

由於您的請求似乎需要很長時間,因此最好使它異步,並避免在等待網絡響應時阻止計時器的ThreadPool線程。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM