Firebase 使任务仅在主线程上执行,导致 Unity 冻结

Posted

技术标签:

【中文标题】Firebase 使任务仅在主线程上执行,导致 Unity 冻结【英文标题】:Firebase makes Tasks execute only on main thread causing Unity to freeze 【发布时间】:2017-06-17 00:03:27 【问题描述】:

我对@9​​87654321@ 的 firebase 1.1.0 有疑问。

一旦我通过FirebaseApp.DefaultInstance.SetEditorDatabaseUrl( myurl ) 激活了firebase,所有不是由firebase 生成的Tasks 都会在主线程上执行。 所以我可以很好地检索和发布数据到 firebase,甚至可以在任务中处理它。它们在单独的线程上运行,我在调试时看到了。但是,当我在某些 MonoBehaviour 的 Start 方法中使用 Task.Run( MyComputingFunction ) 时,Unity 会挂起。假设这个函数只是从0 计数到999999 所以它不是一个锁定 问题。由于任务在主线程上执行,计算时 Unity 会冻结。如果我将 firebase 激活注释掉,我的 task 将在单独的 thread 中运行并且不会冻结 Unity

请帮忙。

这是一个最小的工作示例。将其附加到游戏对象并观察并行运行的任务。取消注释指出的行,任务将按线性顺序执行。

using UnityEngine;
using System;
using System.Threading.Tasks;
using Firebase.Unity.Editor;
using Firebase.Database;

public class NetworkController : MonoBehaviour

    public static DatabaseReference @ref;

    void Start()
    
        // Uncomment line below
        //InitializeDatabase();
        TestStuff();
    

    private void TestStuff()
    
        Task.Run( Counter(1) );
        Task.Run( Counter(2) );
        Task.Run( Counter(3) );
    

    private Action Counter( int i )
    
        return delegate 
            int a = 0;
            while ( a + 10 < 900000 ) 
                a++;
                if ( a % 5000 == 0 )
                    Debug.Log( a + i);
            
        ;
    

    private void InitializeDatabase()
    
        Firebase.FirebaseApp.DefaultInstance.SetEditorDatabaseUrl( "https://dinosaur-facts.firebaseio.com/" );

        @ref = FirebaseDatabase.DefaultInstance.RootReference;
    

【问题讨论】:

你能发布你的代码吗? @MichaelDotKnox 我已经更新了我的帖子。 【参考方案1】:

我是一名 Firebase 工程师,刚刚查看了您的帖子。很抱歉你碰到了这个。

这是我们所依赖的 UnityTask 库中的一个错误。发生的事情是任务库误用 SynchronizationContext.Current(设置时)作为启动任务的工具。 Task.Run 应该始终使用线程池,而不是 SynchronizationContext.Current。 SynchronizationContext.Current 旨在用于编组来自其他线程的调用。

我会在我们这边调查解决这个问题。在此期间,我确实有一个解决方法供您使用。

TaskFactory factory = new TaskFactory(new TaskScheduler(null)); //null = threadpool.
factory.StartNew(() => myFunction());

【讨论】:

此修复的 PR 是 here: 在此修复获得批准之前,您需要使用解决方法。 没问题。非常感谢您的解决方法。 Firebase 很棒,我很高兴您将它集成到 Unity 中。 还没修好? @BenjaminWulfe 问题现在是使用 TaskScheduler(null) 从 TaskFactory 调用 firebase。但是我们不能在该任务函数中调用统一函数。因为必须从unity自己的线程调用unity函数 这不是 firebase 问题。这是一个关于如何使用微软的任务库的问题。如果你需要在某个线程上运行,你应该使用特定的任务调度器。【参考方案2】:

(我是 firebase C++ / Unity 团队的工程师。)

我相信我们在过去的版本中修复了这个问题。 https://firebase.google.com/support/release-notes/unity#4.0.3

最近我们刚刚发布了 4.3.0,据报道,我们对线程和任务进行了多项改进和修复。

【讨论】:

以上是关于Firebase 使任务仅在主线程上执行,导致 Unity 冻结的主要内容,如果未能解决你的问题,请参考以下文章

如何让工作线程在主 UI 线程上执行回调?

在后台线程执行硬任务,在主线程返回结果

如何仅在一个线程上运行任务? [复制]

REDIS事件之EventLoop

为啥我的 AsyncTask 在主线程上运行?

Kotlin + Flow 实现的 Android 应用初始化任务启动库