tanghai 2 سال پیش
والد
کامیت
b8c1f0b858

+ 3 - 3
DotNet/Loader/Init.cs

@@ -18,7 +18,7 @@ namespace ET
 					Log.Error(e.ExceptionObject.ToString());
 				};
 
-				process = Game.Instance.Create(false);
+				process = Game.Instance.Create();
 				
 				// 异步方法全部会回掉到主线程
 				process.AddSingleton<MainThreadSynchronizationContext>();
@@ -27,16 +27,16 @@ namespace ET
 				Parser.Default.ParseArguments<Options>(System.Environment.GetCommandLineArgs())
 					.WithNotParsed(error => throw new Exception($"命令行格式错误! {error}"))
 					.WithParsed(Game.Instance.AddSingleton);
+				Game.Instance.AddSingleton<Logger>().ILog = new NLogger(Options.Instance.AppType.ToString(), Options.Instance.Process, "../Config/NLog/NLog.config");
+				ETTask.ExceptionHandler += Log.Error;
 				
 				process.AddSingleton<TimeInfo>();
-				process.AddSingleton<Logger>().ILog = new NLogger(Options.Instance.AppType.ToString(), Options.Instance.Process, "../Config/NLog/NLog.config");
 				process.AddSingleton<ObjectPool>();
 				process.AddSingleton<IdGenerater>();
 				process.AddSingleton<EventSystem>();
 				process.AddSingleton<TimerComponent>();
 				process.AddSingleton<CoroutineLockComponent>();
 				
-				ETTask.ExceptionHandler += Log.Error;
 				
 				Log.Console($"{Parser.Default.FormatCommandLine(Options.Instance)}");
 

+ 2 - 5
Share/Tool/Init.cs

@@ -7,8 +7,6 @@ namespace ET.Server
 {
     internal static class Init
     {
-        private static Process process;
-        
         private static int Main(string[] args)
         {
             AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
@@ -22,13 +20,12 @@ namespace ET.Server
                 Parser.Default.ParseArguments<Options>(args)
                     .WithNotParsed(error => throw new Exception($"命令行格式错误! {error}"))
                     .WithParsed(Game.Instance.AddSingleton);
+                Game.Instance.AddSingleton<Logger>().ILog = new NLogger(Options.Instance.AppType.ToString(), Options.Instance.Process, "../Config/NLog/NLog.config");
                 
-                process = Game.Instance.Create(false);
+                Process process = Game.Instance.Create(false);
                 // 异步方法全部会回掉到主线程
                 process.AddSingleton<MainThreadSynchronizationContext>();
-				
                 process.AddSingleton<TimeInfo>();
-                process.AddSingleton<Logger>().ILog = new NLogger(Options.Instance.AppType.ToString(), Options.Instance.Process, "../Config/NLog/NLog.config");
                 process.AddSingleton<ObjectPool>();
                 process.AddSingleton<IdGenerater>();
                 

+ 1 - 1
Unity/Assets/Scripts/Core/Module/Log/Logger.cs

@@ -3,7 +3,7 @@ using System.Diagnostics;
 
 namespace ET
 {
-    public class Logger: ProcessSingleton<Logger>
+    public class Logger: Singleton<Logger>
     {
         private ILog iLog;
 

+ 6 - 2
Unity/Assets/Scripts/Core/Singleton/Process.cs

@@ -40,7 +40,7 @@ namespace ET
         private readonly Dictionary<int, ETTask<IResponse>> requestCallbacks = new();
 
         private readonly WaitCallback loop;
-
+        
         private int rpcId;
 
         public void AddMessage(MessageObject messageObject)
@@ -242,13 +242,17 @@ namespace ET
 
         public void Dispose()
         {
-            if (this.Id == 0)
+            int id = this.Id;
+            
+            if (id == 0)
             {
                 return;
             }
             
             this.Id = 0;
             
+            Game.Instance.Remove(id);
+            
             // 顺序反过来清理
             while (singletons.Count > 0)
             {

+ 86 - 35
Unity/Assets/Scripts/Core/World/Game.cs

@@ -1,7 +1,6 @@
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
-using System.Runtime.InteropServices;
 using System.Threading;
 using System.Threading.Tasks;
 
@@ -10,29 +9,36 @@ namespace ET
     public class Game
     {
         [StaticField]
-        public static Game Instance = new Game();
+        public static Game Instance = new();
         
         private Game()
         {
         }
         
-        private readonly Stack<ISingleton> singletons = new();
+        private readonly ConcurrentStack<ISingleton> singletons = new();
 
-        private readonly Queue<ISingleton> updates = new();
+        private readonly ConcurrentQueue<ISingleton> updates = new();
 
-        private readonly Queue<ISingleton> lateUpdates = new();
+        private readonly ConcurrentQueue<ISingleton> lateUpdates = new();
 
-        private readonly Queue<ISingleton> loads = new();
+        private readonly ConcurrentQueue<ISingleton> loads = new();
 
+        #region 线程安全
+
+        private bool needLoad;
+        
         private readonly ConcurrentQueue<Process> loops = new();
 
         private readonly ConcurrentDictionary<int, Process> processes = new();
+        
+        private readonly Queue<ETTask> frameFinishTask = new();
 
-        private int idGenerate;
+        private int idGenerator;
 
         public Process Create(bool loop = true)
         {
-            Process process = new(++this.idGenerate);
+            int id = Interlocked.Increment(ref this.idGenerator);
+            Process process = new(id);
             this.processes.TryAdd(process.Id, process);
             if (loop)
             {
@@ -43,56 +49,92 @@ namespace ET
         
         public void Remove(int id)
         {
-            if (this.processes.Remove(id, out Process thread))
+            if (this.processes.Remove(id, out Process process))
             {
-                thread.Dispose();    
+                process.Dispose();    
             }
         }
         
+        public async ETTask WaitGameFrameFinish()
+        {
+            ETTask task = ETTask.Create(true);
+            frameFinishTask.Enqueue(task);
+            await task;
+        }
+        
+        private void FrameFinishUpdateInner()
+        {
+            while (frameFinishTask.Count > 0)
+            {
+                ETTask task = frameFinishTask.Dequeue();
+                task.SetResult();
+            }
+        }
+
+        public void Load()
+        {
+            this.needLoad = true;
+        }
         
-        // 简单线程调度,每次Loop会把所有Game Loop一遍
+        // 简单线程调度,每次Loop会把所有Process Loop一遍
         public void Loop()
         {
             int count = this.loops.Count;
 
-            using Barrier barrier = new Barrier(1);
+            using Barrier barrier = new(1);
             
             while (count-- > 0)
             {
-                this.loops.TryDequeue(out Process thread);
-                if (thread == null)
+                this.loops.TryDequeue(out Process process);
+                if (process == null)
                 {
                     continue;
                 }
                 barrier.AddParticipant();
-                thread.Barrier = barrier;
-                if (thread.Id == 0)
+                process.Barrier = barrier;
+                if (process.Id == 0)
                 {
                     continue;
                 }
-                this.loops.Enqueue(thread);
-                ThreadPool.QueueUserWorkItem(thread.Loop);
+                this.loops.Enqueue(process);
+                ThreadPool.QueueUserWorkItem(process.Loop);
             }
 
             barrier.SignalAndWait();
+            
+            // 此时没有线程竞争,进行 Load Update LateUpdate等操作
+            if (this.needLoad)
+            {
+                this.needLoad = false;
+                this.LoadInner();
+            }
+            this.UpdateInner();
+            this.LateUpdateInner();
+            this.FrameFinishUpdateInner();
         }
 
-        public void Send(int threadId, MessageObject messageObject)
+        #endregion
+
+
+        public void Send(int processId, MessageObject messageObject)
         {
-            if (this.processes.TryGetValue(threadId, out Process thread))
+            if (this.processes.TryGetValue(processId, out Process process))
             {
                 return;
             }
-            thread.AddMessage(messageObject);
+            process.AddMessage(messageObject);
         }
         
-        
-        
-        
-        
+        // 为了保证线程安全,只允许在Start之前AddSingleton,主要用于线程共用的一些东西
+        public T AddSingleton<T>() where T: Singleton<T>, new()
+        {
+            T singleton = new T();
+            AddSingleton(singleton);
+            return singleton;
+        }
+
         public void AddSingleton(ISingleton singleton)
         {
-            
             singleton.Register();
             
             singletons.Push(singleton);
@@ -117,13 +159,16 @@ namespace ET
                 loads.Enqueue(singleton);
             }
         }
-        
-        public void Update()
+
+        private void UpdateInner()
         {
             int count = updates.Count;
             while (count-- > 0)
             {
-                ISingleton singleton = updates.Dequeue();
+                if (!updates.TryDequeue(out ISingleton singleton))
+                {
+                    continue;
+                }
 
                 if (singleton.IsDisposed())
                 {
@@ -146,14 +191,17 @@ namespace ET
                 }
             }
         }
-        
-        public void LateUpdate()
+
+        private void LateUpdateInner()
         {
             int count = lateUpdates.Count;
             while (count-- > 0)
             {
-                ISingleton singleton = lateUpdates.Dequeue();
-                
+                if (!lateUpdates.TryDequeue(out ISingleton singleton))
+                {
+                    continue;
+                }
+
                 if (singleton.IsDisposed())
                 {
                     continue;
@@ -176,12 +224,15 @@ namespace ET
             }
         }
 
-        public void Load()
+        private void LoadInner()
         {
             int count = loads.Count;
             while (count-- > 0)
             {
-                ISingleton singleton = loads.Dequeue();
+                if (!this.loads.TryDequeue(out ISingleton singleton))
+                {
+                    continue;
+                }
                 
                 if (singleton.IsDisposed())
                 {

+ 11 - 3
Unity/Assets/Scripts/Loader/MonoBehaviour/Init.cs

@@ -1,5 +1,5 @@
 using System;
-using System.Threading;
+using System.Threading.Tasks;
 using CommandLine;
 using UnityEngine;
 
@@ -23,6 +23,7 @@ namespace ET
 			Parser.Default.ParseArguments<Options>(args)
 				.WithNotParsed(error => throw new Exception($"命令行格式错误! {error}"))
 				.WithParsed(Game.Instance.AddSingleton);
+			Game.Instance.AddSingleton<Logger>().ILog = new UnityLogger();
 			
 			process = Game.Instance.Create(false);
 				
@@ -33,7 +34,6 @@ namespace ET
 			Options.Instance.StartConfig = $"StartConfig/Localhost";
 
 			process.AddSingleton<TimeInfo>();
-			process.AddSingleton<Logger>().ILog = new UnityLogger();
 			process.AddSingleton<ObjectPool>();
 			process.AddSingleton<IdGenerater>();
 			process.AddSingleton<EventSystem>();
@@ -43,6 +43,14 @@ namespace ET
 			ETTask.ExceptionHandler += Log.Error;
 
 			process.AddSingleton<CodeLoader>().Start();
+
+			Task.Run(() =>
+			{
+				while (true)
+				{
+					Game.Instance.Loop();
+				}
+			});
 		}
 
 		private void Update()
@@ -58,7 +66,7 @@ namespace ET
 
 		private void OnApplicationQuit()
 		{
-			Game.Instance.Remove(this.process.Id);
+			this.process.Dispose();
 		}
 	}
 	

+ 9 - 10
Unity/Assets/Scripts/ThirdParty/ETTask/ETTask.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Runtime.CompilerServices;
@@ -19,8 +20,7 @@ namespace ET
             }
         }
 
-        [ThreadStatic]
-        private static readonly Queue<ETTask> queue = new Queue<ETTask>();
+        private static readonly ConcurrentQueue<ETTask> queue = new();
 
         /// <summary>
         /// 请不要随便使用ETTask的对象池,除非你完全搞懂了ETTask!!!
@@ -33,12 +33,11 @@ namespace ET
             {
                 return new ETTask();
             }
-            
-            if (queue.Count == 0)
+            if (!queue.TryDequeue(out ETTask task))
             {
-                return new ETTask() {fromPool = true};    
+                return new ETTask() {fromPool = true}; 
             }
-            return queue.Dequeue();
+            return task;
         }
 
         private void Recycle()
@@ -166,7 +165,7 @@ namespace ET
     [AsyncMethodBuilder(typeof (ETAsyncTaskMethodBuilder<>))]
     public class ETTask<T>: ICriticalNotifyCompletion
     {
-        private static readonly Queue<ETTask<T>> queue = new Queue<ETTask<T>>();
+        private static readonly ConcurrentQueue<ETTask<T>> queue = new();
         
         /// <summary>
         /// 请不要随便使用ETTask的对象池,除非你完全搞懂了ETTask!!!
@@ -180,11 +179,11 @@ namespace ET
                 return new ETTask<T>();
             }
             
-            if (queue.Count == 0)
+            if (!queue.TryDequeue(out ETTask<T> task))
             {
-                return new ETTask<T>() { fromPool = true };    
+                return new ETTask<T>() {fromPool = true}; 
             }
-            return queue.Dequeue();
+            return task;
         }
         
         private void Recycle()