WinRT的:封锁任务 [英] WinRT: blocking Task

查看:91
本文介绍了WinRT的:封锁任务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我实现网络层我的应用程序,即使用异步JSON-RPC协议。

I'm implementing network layer of my application, that is using an asynchronous JSON-RPC protocol.

为了与服务器通信,想我做出会发送一个适当的请求,等待服务器响应发送,并返回它的方法。一切都与使用异步电动机/等待关键字。

In order to communicate with the server, i'd like to make a method that will send a proper request, wait until the server sends response, and return it. Everything with use of async/await keywords.

下面是简单的示例code:

Here's simplified sample code:

字符串响应;

Task<string> SendRequest(string methodName, string methodParams)
{
    string request = generateRequest(methodName, methodParams);

    await Send(request); // this will send using DataWriter, and StreamSocket

    // block Task until response arrives

    return response;
}


async void ReceiveLoop()
{
    while (true)
    {
            uint numStrBytes = await _reader.LoadAsync(BufferSize);

            string msg = _reader.ReadString(numStrBytes);

            response = msg;

            // unblock previously blocked SendRequest
        }        
    }
}

async void main()
{
    RecieveLoop();  
}

async void SendButtonPressed()
{
    string response = await SendRequest("Test method", "Test params");

    Debug.WriteLine("Response = " + response);
}

的主要问题与该图形这个阻击战。这个动作应该阻止当前的任务,并允许处理超时。
我试着使用的ManualResetEvent和了WaitOne(int)以处理这个问题,但它冻结整个主题,因为我使用异步/只等待着,它冻结整个应用程序(UI线程对我来说更precise)。

The main problem with this pattern it this blocking action. This action should block current Task, and allow to handle timeout. I've tried to use ManualResetEvent, and WaitOne(int) to handle this, but it freezes whole Thread, and because I'm using async/await only, it freezes whole application (UI Thread to me more precise).

解决方案,这看起来对我来说相当哈克是,我可以用Task.Delay与CancellationTokens。

The solution, that looks quite hacky for me is that I can use Task.Delay with CancellationTokens.

它看起来是这样的:

...
CancellationTokenSource cts;
int timeout = 10000;

Task<string> SendRequest(string methodName, string methodParams)
{
    ... (prepare request, and send)

    cts = new CancellationTokenSource();

    try
    {
        await Task.Delay(timeout, cts.Token);
    } catch(TaskCanceledException)
    {

    }

    // do rest
}

async void ReceiveLoop()
{
    // init recieve loop, and recieve message

    cts.Cancel();      
}

与解决方案(除了它看起来像一个黑客)问题是性能 - 每一个请求有抛出EXCETION,需要处理(在这种情况下跳过)。这一个是缓慢的,它伤害:)

The problem with that solution (besides it looks like a hack) is performance - every request there is an excetion thrown, that needs to be handled (skipped in that case). This one is slow, and it hurts :)

我怎么能做到这一点更优雅的方式?是否有任何其他选项来阻止任务?

How can I do it in more elegant way? Is there any other option to block a Task?

推荐答案

转换接收和发送循环为一个循环,由发送按钮触发时:

Convert the receive and send loops into one loop that is trigged by the send button:

while(!cancel) {
    await sendRequest();
    await receiveResponse();
}

不知道,如果你甚至需要循环再因为我不知道您的具体要求。它可能是这样的:

Not sure if you even need the loop then because I don't know your exact requirements. It could look like this:

await sendRequest();
await receiveResponse();

这将执行一个请求 - 响应周期。

That would execute a single request-response-cycle.

阅读您的评论下面我想补充以下几点:你说的没错,现在你需要两个循环。我想首先创建一个类解决这个重新present的要求是在飞行中:

Reading your comment below I want to add the following: You're right, now you need both loops. I'd tackle this by first creating a class to represent a request that is in flight:

class Request { int ID; object Response; TaskCompletionCource CompletedTask; }

当发送的东西,你创建这个类的一个实例,并将其添加到词典&LT; INT,请求&GT; 。在 ID 是一个共享的标识符,该服务器可以使用您的请求作出回应(我的理解可将多个请求突出)。

When sending something, you create an instance of this class and add it to a Dictionary<int, Request>. The ID is a shared identifier that the server can use to respond to your request (I understand multiple requests can be outstanding).

当接收到响应您保存结果并标记 CompletedTask 已完成。酸酸的发送方法应该是这样的:

When receiving a response you save the result and mark the CompletedTask as completed. Sour send method should look like:

var request = CreateRequest();
await sendRequest(request);
await request.CompletedTask.Task;
return request.Response;

TaskCompletionSource 将作为一个事件。在请求类封装了所有相关的数据。

The TaskCompletionSource will act as an event. The Request class encapsulates all related data.

这篇关于WinRT的:封锁任务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆