简体   繁体   English

C#异步等待池

[英]C# async await for pooling

I need to do some WebRequest to a certain endpoint every 2 seconds. 我需要每2秒对某个端点执行一些WebRequest。 I tried to do it with a Timer, the problem is that every call to the callback function is creating a different Thread and I'm havind some concurrence problems. 我尝试使用Timer来完成此操作,问题是每次对回调函数的调用都在创建一个不同的线程,并且我遇到了一些并发问题。 So I decided to change my implementation and I was thinking about using a background worker with a sleep of two seconds inside or using async await but I don't see the advantages of using async await. 因此,我决定更改实现,当时我正在考虑使用内部睡眠时间为两秒钟的后台工作程序或使用异步等待,但是我看不到使用异步等待的好处。 Any advice? 有什么建议吗? thank you. 谢谢。

This is the code that I will reimplement. 这是我将重新实现的代码。

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();
    }
}

EDIT: I have read this SO thread Async/await vs BackgroundWorker 编辑:我已阅读此SO线程Async / await与BackgroundWorker

async await is also concurrence. 异步等待也是并发的。 If you have concurrence problems and you want your application to have only one thread, you should avoid using async await. 如果您有并发问题,并且您希望应用程序只有一个线程,则应避免使用异步等待。

However the best way to do WebRequest is to use async await, which does not block the main UI thread. 但是,执行WebRequest的最佳方法是使用异步等待,它不会阻塞主UI线程。

Use the bellow method, it will not block anything and it is recommended by Microsoft. 使用波纹管方法,它不会阻塞任何东西,Microsoft建议。 https://msdn.microsoft.com/en-us/library/86wf6409(v=vs.110).aspx 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();
    }
}

You don't mention what the concurrency problems are. 您没有提到并发问题。 It may be that the request takes so long that the next one starts before the previous one finishes. 该请求可能花费了很长时间,以至于下一个请求开始之前的请求结束。 It could also be that the callback replaces the value in my_Object while readers are accessing it. 也可能是当读者访问它时,回调替换了my_Object的值。

You can easily make a request every X seconds, asynchronously and without blocking, by using Task.Delay , eg: 您可以使用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);
    }
}

This will result in a polling call X seconds after the last one finishes. 最后一个结束后X秒钟将导致轮询呼叫。

It also avoids concurrency issues by storing the result in a concurrent queue instead of replacing the old value, perhaps while someone else was reading int. 它还通过将结果存储在并发队列中而不是替换旧值(可能是在其他人正在读取int时)来避免并发问题。

Consumers of MyObject would call Dequeue to retrieve MyObject instances in the order they were received. MyObject的使用者将调用Dequeue来按其接收顺序检索MyObject实例。

You could use the ConcurrentQueue to fix the current code too: 您也可以使用ConcurrentQueue来修复当前代码:

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

or 要么

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

if you want to change your GetObject method to work asynchronously. 如果您想将GetObject方法更改为异步工作。

Since your request seems to take a long time, it's a good idea to make it asynchronous and avoid blocking the timer's ThreadPool thread while waiting for a network response. 由于您的请求似乎需要很长时间,因此最好使它异步,并避免在等待网络响应时阻止计时器的ThreadPool线程。

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

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