C#-调用Task.Result是否等到返回结果后再返回

时间:2019-11-27 21:04:33

标签: c# unity3d task

这是我的代码:

public void ConnectToWorldServer()
{
    if (socketReady)
    {
        return;
    }
    //Default host and port values;
    string host = ClientWorldServer.ServerIP;
    int port = ClientWorldServer.TCPPort;

    //ClientLoginServer ClientLoginServer = new ClientLoginServer();


    try
    {

        socket = new TcpClient(host, port);
        stream = socket.GetStream();
        socket.NoDelay = true;
        writer = new StreamWriter(stream);
        reader = new StreamReader(stream);
        socketReady = true;
        //Preserve the connection to worldserver thrue scenes
        UnityThread.executeInUpdate(() =>
        {
            DontDestroyOnLoad(worldserverConnection);
        });

        // Start listening for connections.
        while (true)
        {
            if (socketReady)
            {
                if (stream.DataAvailable)
                {
                    string sdata = reader.ReadLine();
                    if (sdata != null)
                    {

                        Task<JsonData> jsonConvert = Task<JsonData>.Factory.StartNew(() => convertJson(sdata));
                        UnityThread.executeInUpdate(() =>
                        {
                            OnIncomingData(jsonConvert.Result);
                        });
                    }
                }
            }
        }
    }
    catch (Exception e)
    {
        Debug.Log("Socket error : " + e.Message);
    }

}

private JsonData convertJson(string data)
{
    return JsonConvert.DeserializeObject<JsonData>(data);    
}

我现在想知道的是这部分代码:

UnityThread.executeInUpdate(() =>
{
    OnIncomingData(jsonConvert.Result);
});

阻止,直到此任务返回结果:

Task<JsonData> jsonConvert = Task<JsonData>.Factory.StartNew(() => convertJson(sdata));

我对Tasks确实不那么熟悉。我的目标是运行json转换,然后执行OnIncomingData(jsonConvert.Result);

我认为我的代码没有这样做。为什么?

2 个答案:

答案 0 :(得分:1)

当线程调用Task.Result时,它将阻塞,直到任务完成为止,方法是返回值,引发异常或被取消。来自the documentation

  

访问属性的get访问器会阻塞调用线程,直到异步操作完成为止;等效于调用Wait方法。

因此,很明显,调用Task<JsonData>.Factory.StartNew会创建一个Task(代表要执行的某些计算),并安排执行时间(何时执行以及在哪个线程上执行)。默认TaskScheduler,但StartNew应该立即返回)。这样,您无需等待创建的UnityThread.executeInUpdate即可调用Task。在UnityThread调用传递给executeInUpdate的匿名函数的时刻,该线程将阻塞,直到Task完成。我对UnityThread.executeInUpdate不熟悉,所以我无法告诉您在回调完成之前它是否会阻塞。

要注意的一件事是,根据Unity与线程的工作方式,可以通过访问Result属性来创建死锁。在某些情况下,任务会尝试使用特定的上下文来执行,并且如果您使该上下文受阻而无法等待任务完成,则它将永远无法运行:https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

答案 1 :(得分:1)

如果您要等待结果,那么使用Task的意义是什么?异步执行操作的正确方法是使函数始终保持异步状态。

public async void ConnectToWorldServer()
{
   .....
   .....
// Here await will put this method call on a queue to finish later and will return from this method. 
         Task<JsonData> jsonConvert = await Task<JsonData>.Factory.StartNew(() => convertJson(sdata));
// After the task is finished, it will resume to this method here to execute next statement. 
         UnityThread.executeInUpdate(() =>
         {
            OnIncomingData(jsonConvert.Result);
         });
   .....
   .....
}