Zenject与UniRx结合实现跨线程通信Signal
- 修改Zenject下ProfileBlock.cs源码, 取消有关UnityEngine.Profiling.Profiler的代码.
- 然后使用Zenject的Signal:
// 定义Signal public class TestCrossThreadCommEvent : Signal<string, TestCrossThreadCommEvent> { }
1 // Install Signals 2 Container.DeclareSignal<TestCrossThreadCommEvent>();
1 // 启动线程 2 tth = new Thread(() => 3 { 4 while (true) 5 { 6 Thread.Sleep(1000); 7 _crossThreadCommEvent.Fire("fire not in main thread"); 8 //_unityEvent.Invoke(); 9 } 10 }); 11 tth.Start(); 12 // UniRx 13 _crossThreadCommEvent.AsObservable.ObserveOnMainThread(MainThreadDispatchType.Update) 14 // 使用lambda表达式是没有问题的 15 .Subscribe(s => TestCrossThreadComm(s)) 16 .AddTo(this); 17 18 void TestCrossThreadComm(string msg) 19 { 20 Debug.Log(Thread.CurrentThread.ManagedThreadId); 21 Debug.Log(msg); 22 transform.RotateAround(transform.position, Vector3.up, 5f); 23 }
- 输出结果:
UnityEngine.Debug:Log(Object)
fire not in main thread
UnityEngine.Debug:Log(Object) - 多个参数情况:
1 // 定义Signal 2 public class TestCrossThreadCommEvent : Signal<string, string, TestCrossThreadCommEvent> { }
1 // Install Signals 2 Container.DeclareSignal<TestCrossThreadCommEvent>();
1 // 启动线程 2 tth = new Thread(() => 3 { 4 while (true) 5 { 6 Thread.Sleep(1000); 7 _crossThreadCommEvent.Fire("fire not in main thread", "\t so happy."); 8 //_unityEvent.Invoke(); 9 } 10 }); 11 tth.Start(); 12 // UniRx-Lambda 13 _crossThreadCommEvent.AsObservable.ObserveOnMainThread(MainThreadDispatchType.Update) 14 // 使用lambda表达式是没有问题的 15 .Subscribe(tuple => 16 { 17 Debug.Log(Thread.CurrentThread.ManagedThreadId); 18 Debug.Log(tuple.Item1 + tuple.Item2); 19 transform.RotateAround(transform.position, Vector3.up, 5f); 20 }) 21 .AddTo(this);
- 输出结果:
1
UnityEngine.Debug:Log(Object)
fire not in main thread so happy.
UnityEngine.Debug:Log(Object)
以上为Asset Store中Zenject早期版本.
目前有版本对Signal部分改动如下:
1 ... 2 #if UNITY_EDITOR && ZEN_PROFILING_ENABLED 3 using (ProfileBlock.Start("Signal '{0}'", this.GetType().Name)) 4 #endif 5 { 6 var wasHandled = Manager.Trigger(SignalId, new object[0]); 7 8 wasHandled |= (_listeners.Count > 0); 9 10 // Iterate over _tempListeners in case the 11 // listener removes themselves in the callback 12 // (we use _tempListeners to avoid memory allocs) 13 _tempListeners.Clear(); 14 15 for (int i = 0; i < _listeners.Count; i++) 16 { 17 _tempListeners.Add(_listeners[i]); 18 } 19 20 for (int i = 0; i < _tempListeners.Count; i++) 21 { 22 var listener = _tempListeners[i]; 23 24 #if UNITY_EDITOR && ZEN_PROFILING_ENABLED 25 using (ProfileBlock.Start(listener.ToDebugString())) 26 #endif 27 { 28 listener(); 29 } 30 } 31 32 #if ZEN_SIGNALS_ADD_UNIRX 33 wasHandled |= _observable.HasObservers; 34 #if UNITY_EDITOR && ZEN_PROFILING_ENABLED 35 using (ProfileBlock.Start("UniRx Stream")) 36 #endif 37 { 38 _observable.OnNext(Unit.Default); 39 } 40 #endif 41 ...
涉及到ProfileBlock的使用ZEN_PROFILING_ENABLED来开启, 所以想用Signal跨线程通信,否决掉ZEN_PROFILING_ENABLED就可以了.