首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >C# -统一3d等待任务在主线程中完成

C# -统一3d等待任务在主线程中完成
EN

Stack Overflow用户
提问于 2022-05-17 14:15:32
回答 1查看 630关注 0票数 1

我使用Unity3D,我想在主线程中运行任务并等待它完成。

这是我的代码:

代码语言:javascript
运行
复制
public override Task<Vibranium.Protobuffers.ACSpawnData> WorldObjectSpawned(Vibranium.Protobuffers.WorldObjectData request, ServerCallContext context)
{
    ACSpawnData acSpawnData = new ACSpawnData();
    
    IEnumerator SpawnGo(ACSpawnData acSpawnData)
    {
        int spawnId = WorldObjectManager.Instance.GetWorldObjects.Count + 1;
        GameObject spawnedGO = GameObject.CreatePrimitive(PrimitiveType.Cube);
        spawnedGO.name = spawnId.ToString();
        spawnedGO.transform.SetParent(WorldObjectManager.Instance.transform);
        
        if (request.WorldObjectType == WorldObjectType.Player)
        {
            spawnedGO.GetComponent<Renderer>().material.color = Color.red;
        }
    
        WorldObjectManager.Instance.GetWorldObjects.Add(spawnedGO);

        acSpawnData.SpawnId = (uint)spawnId;
        acSpawnData.WorldObjectType = request.WorldObjectType;            


        yield return null;
    }   
    

    MainThreadDispatcher.Instance().Enqueue(SpawnGo(acSpawnData));
        
    return Task.FromResult(acSpawnData);
}

要在主线程中执行IEnumerator,我使用以下命令:

代码语言:javascript
运行
复制
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.Threading.Tasks;

/// Author: Pim de Witte (pimdewitte.com) and contributors, https://github.com/PimDeWitte/UnityMainThreadDispatcher
/// <summary>
/// A thread-safe class which holds a queue with actions to execute on the next Update() method. It can be used to make calls to the main thread for
/// things such as UI Manipulation in Unity. It was developed for use in combination with the Firebase Unity plugin, which uses separate threads for event handling
/// </summary>
public class MainThreadDispatcher : MonoBehaviour {

    private static readonly Queue<Action> _executionQueue = new Queue<Action>();

    public void Update() {
        lock(_executionQueue) {
            while (_executionQueue.Count > 0) {
                _executionQueue.Dequeue().Invoke();
            }
        }
    }

    /// <summary>
    /// Locks the queue and adds the IEnumerator to the queue
    /// </summary>
    /// <param name="action">IEnumerator function that will be executed from the main thread.</param>
    public void Enqueue(IEnumerator action) {
        lock (_executionQueue) {
            _executionQueue.Enqueue (() => {
                StartCoroutine (action);
            });
        }
    }

        /// <summary>
        /// Locks the queue and adds the Action to the queue
    /// </summary>
    /// <param name="action">function that will be executed from the main thread.</param>
    public void Enqueue(Action action)
    {
        Enqueue(ActionWrapper(action));
    }
    
    /// <summary>
    /// Locks the queue and adds the Action to the queue, returning a Task which is completed when the action completes
    /// </summary>
    /// <param name="action">function that will be executed from the main thread.</param>
    /// <returns>A Task that can be awaited until the action completes</returns>
    public Task EnqueueAsync(Action action)
    {
        var tcs = new TaskCompletionSource<bool>();

        void WrappedAction() {
            try 
            {
                action();
                tcs.TrySetResult(true);
            } catch (Exception ex) 
            {
                tcs.TrySetException(ex);
            }
        }

        Enqueue(ActionWrapper(WrappedAction));
        return tcs.Task;
    }

    
    IEnumerator ActionWrapper(Action a)
    {
        a();
        yield return null;
    }


    private static MainThreadDispatcher _instance = null;

    public static bool Exists() {
        return _instance != null;
    }

    public static MainThreadDispatcher Instance() {
        if (!Exists ()) {
            throw new Exception ("UnityMainThreadDispatcher could not find the UnityMainThreadDispatcher object. Please ensure you have added the MainThreadExecutor Prefab to your scene.");
        }
        return _instance;
    }


    void Awake() {
        if (_instance == null) {
            _instance = this;
            DontDestroyOnLoad(this.gameObject);
        }
    }

    void OnDestroy() {
            _instance = null;
    }


}

一切都很好。创建游戏对象时,Task.FromResult不会等待SpawnGo填充acSpawnData,因此acSpawnData总是空的。

如何阻止任务WorldObjectSpawned的执行,直到IEnumerator SpawnGo完成任务并填充acSpawnData以便返回为止?

EN

回答 1

Stack Overflow用户

发布于 2022-05-17 14:49:18

与其直接使用自己的线程处理,不如利用C#的内置异步/等待

它允许您派生任务,这些任务为您管理线程,然后您可以决定什么时候需要等待任务完成才能继续。

作为一个副作用,它也将显着地简化和减少您的代码。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72275646

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档