lith 4 anni fa
parent
commit
d1b67d0ed1

+ 44 - 0
dotnet/Doc/PublishFile/Sers单体压测/ServiceCenter/Data/App.Robot.json

@@ -0,0 +1,44 @@
+{
+  "tasks": {
+    "1": {
+      "id": 1,
+      "sumCount": 0,
+      "sumFailCount": 0,
+      "curCount": 0,
+      "failCount": 0,
+      "targetCount": 1000000000,
+      "config": {
+        "type": "ApiClient",
+        "name": "saveToCache",
+        "apiRoute": "/_robot_/taskMng/saveToCache",
+        "threadCount": 1,
+        "loopCountPerThread": 1000000000,
+        "interval": 5000,
+        "autoStart": true,
+        "logError": true
+      },
+      "RunningThreadCount": 1,
+      "IsRunning": true
+    },
+    "2": {
+      "id": 2,
+      "sumCount": 0,
+      "sumFailCount": 0,
+      "curCount": 0,
+      "failCount": 0,
+      "targetCount": 8000000000,
+      "config": {
+        "type": "ApiClientAsync",
+        "name": "Async",
+        "apiRoute": "/a",
+        "threadCount": 8,
+        "loopCountPerThread": 1000000000,
+        "interval": 0,
+        "autoStart": true,
+        "logError": false
+      },
+      "RunningThreadCount": 0,
+      "IsRunning": false
+    }
+  }
+}

+ 1 - 1
dotnet/Doc/PublishFile/Sers单体压测/ServiceCenter/appsettings.json

@@ -52,7 +52,7 @@
     "LocalApiService": {
 
       /* 后台服务的线程个数(单位个,默认0,代表不开启服务)*/
-      "workThreadCount": 4,
+      "workThreadCount": 8,
 
       /* 超时时间,若不指定则后台任务永不超时。(主动关闭超过此时间的任务,实际任务强制关闭的时间会在1倍超时时间到2倍超时时间内)。单位:ms。*/
       //"timeout_ms": 10000,

+ 5 - 25
dotnet/ServiceStation/Demo/StressTest/App.Robot.Station/Controllers/TaskController.cs

@@ -3,30 +3,18 @@ using App.Robot.Station.Logical;
 using Sers.SersLoader;
 using Sers.SersLoader.ApiDesc.Attribute.Valid;
 using Sers.Core.Module.Rpc;
-using Sers.Core.Module.App;
 using Vit.Core.Util.ComponentModel.Api;
 using Vit.Core.Util.ComponentModel.Data;
-using Vit.Core.Util.Threading;
-using App.Robot.Station.Logical.Worker;
 
 namespace App.Robot.Station.Controllers
 {
     public class TaskController : IApiController
     {
-        /// <summary>
-        ///  主线程开启的常驻线程,用以启动api触发的任务。
-        ///  若在api中直接调用,则会导致 ApiClient中 RpcData错乱的问题
-        ///  (RpcData通过AsyncCache保存api调用关系,故若api中直接开启线程调用api,可能会出现api中的 RpcData错乱)。
-        /// </summary>
-        public static readonly TaskQueue MainTask = new TaskQueue() { threadName = "Robot-MainTaskToStartTask" };
 
         static TaskController()
         {
-            //TaskController.MainTask
-            SersApplication.onStart += () => TaskController.MainTask.Start();
-            SersApplication.onStop += () => TaskController.MainTask.Stop();
-        }
- 
+            TaskMng.Init();
+        } 
 
         /// <summary>
         /// 保存到Cache
@@ -47,7 +35,7 @@ namespace App.Robot.Station.Controllers
         /// <returns>ArgModelDesc-returns</returns>
         [SsRoute("task/getAll")]
         [SsCallerSource(ECallerSource.Internal)]
-        public ApiReturn<List<IWorker>> GetAll()
+        public ApiReturn<List<TaskItem>> GetAll()
         {
             return TaskMng.Instance.GetAll();
         }
@@ -62,11 +50,7 @@ namespace App.Robot.Station.Controllers
         [SsCallerSource(ECallerSource.Internal)]
         public ApiReturn Add(TaskConfig config)
         {
-            MainTask.AddTask(() =>
-            {
-                TaskMng.Instance.Add(config);
-            });
-            return true;
+            return TaskMng.Instance.Add(config);         
         }
 
 
@@ -74,11 +58,7 @@ namespace App.Robot.Station.Controllers
         [SsCallerSource(ECallerSource.Internal)]
         public ApiReturn Start(int id)
         {
-            MainTask.AddTask(() =>
-            {
-                TaskMng.Instance.Start(id);
-            });
-            return true;
+            return TaskMng.Instance.Start(id);
         }
 
         [SsRoute("task/stop")]

+ 5 - 5
dotnet/ServiceStation/Demo/StressTest/App.Robot.Station/Logical/TaskConfig.cs

@@ -17,12 +17,12 @@
 
 
 
-        public long threadCount =1;
+        public long threadCount = 1;
+
+        public long loopCountPerThread = 2000;
+
 
-        public long loopCountPerThread =2000;     
-        
 
- 
         /// <summary>
         /// 每次调用时间间隔。(单位:ms)
         /// </summary>
@@ -33,7 +33,7 @@
         /// <summary>
         /// 失败时是否控制台输出
         /// </summary>
-        public bool logError = false;
+        public bool logError = false; 
 
     }
 }

+ 63 - 0
dotnet/ServiceStation/Demo/StressTest/App.Robot.Station/Logical/TaskItem.cs

@@ -0,0 +1,63 @@
+using System.Runtime.CompilerServices;
+using System.Threading;
+using App.Robot.Station.Logical.Worker;
+using Newtonsoft.Json;
+
+namespace App.Robot.Station.Logical
+{
+    public class TaskItem
+    {
+        public int id;
+
+        public long sumCount = 0;
+        public long sumFailCount = 0;
+
+        public long curCount = 0;
+        public long failCount = 0;
+
+        public long targetCount { get; private set; }
+
+
+        public TaskConfig config { get => config_;  set { config_ = value; EventAfterSetConfig(); }  }
+        private TaskConfig config_;
+
+
+        public int RunningThreadCount => worker.RunningThreadCount;
+
+        public bool IsRunning => worker.IsRunning;
+
+
+        [JsonIgnore]
+        public IWorker worker { get; private set; }
+
+        void EventAfterSetConfig() 
+        {
+            var config = config_;
+
+            targetCount = config.threadCount * config.loopCountPerThread;
+
+            switch (config.type)
+            {
+                case "ApiClientAsync": worker = new Worker_ApiClientAsync(this); break;
+                case "HttpClient": worker = new Worker_HttpClient(this); break;
+                case "HttpUtil": worker = new Worker_HttpUtil(this); break;
+                default: config.type = "ApiClient"; worker = new Worker_ApiClient(this); break;
+            }
+        }
+
+
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public void StepUp(bool success)
+        {
+            Interlocked.Increment(ref curCount);
+            Interlocked.Increment(ref sumCount);
+            if (!success)
+            {
+                Interlocked.Increment(ref sumFailCount);
+                Interlocked.Increment(ref failCount);
+            }
+
+        }
+    }
+}

+ 70 - 41
dotnet/ServiceStation/Demo/StressTest/App.Robot.Station/Logical/TaskMng.cs

@@ -2,33 +2,54 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Threading;
-using App.Robot.Station.Logical.Worker;
 using Newtonsoft.Json;
+using Sers.Core.Module.App;
 using Vit.Core.Util.ConfigurationManager;
+using Vit.Core.Util.Threading;
 
 namespace App.Robot.Station.Logical
 {
     public class TaskMng
     {
-        static TaskMng LoadTaskMng()
+        public static void Init()
         {
-            var taskMng = JsonFile.GetFromFile<TaskMng>(new[] { "Data", "App.Robot.json" }) ;
+        }
 
-            if (null == taskMng)
-            {
-                taskMng= new TaskMng();
-            }
 
-            taskMng.tasks.Values.Where(m => m.config.autoStart).ToList().ForEach(task => task.Start());
-            return taskMng;
-        }
+        /// <summary>
+        ///  主线程开启的常驻线程,用以启动api触发的任务。
+        ///  若在api中直接调用,则会导致 ApiClient中 RpcData错乱的问题
+        ///  (RpcData通过AsyncCache保存api调用关系,故若api中直接开启线程调用api,可能会出现api中的 RpcData错乱)。
+        /// </summary>
+        public static readonly TaskQueue MainTask = new TaskQueue() { threadName = "Robot-MainTaskToStartTask" };
 
-        public static readonly TaskMng Instance = LoadTaskMng();
+        public static readonly TaskMng Instance;
+       
+        static TaskMng()
+        {
+            //TaskController.MainTask
+            SersApplication.onStart += () => MainTask.Start();
+            SersApplication.onStop += () => MainTask.Stop();
 
+            Instance = JsonFile.GetFromFile<TaskMng>(new[] { "Data", "App.Robot.json" }) ;
 
+            if (null == Instance)
+            {
+                Instance = new TaskMng();
+            }
 
+            MainTask.AddTask(() =>
+            {
+                Thread.Sleep(2000);
+                Instance.tasks.Values.Where(m => m.config.autoStart).ToList().ForEach(task => task.worker.Start());
+            });
 
+          
+         
+        }
 
+      
+                     
         public void TaskMngSaveToCache()
         {
             JsonFile.SetToFile(this, new[] { "Data", "App.Robot.json" });
@@ -37,43 +58,48 @@ namespace App.Robot.Station.Logical
 
 
         [JsonProperty]
-         ConcurrentDictionary<int, IWorker> tasks = new ConcurrentDictionary<int, IWorker>();
-        [JsonProperty]
-        int curKeyIndex = 0;
-
+        ConcurrentDictionary<int, TaskItem> tasks = new ConcurrentDictionary<int, TaskItem>();
 
+               
 
-        public TaskMng()
-        {
-        }
-
-     
-
-        private int GetNewKey() => Interlocked.Increment(ref curKeyIndex);
 
-       
         public bool Add(TaskConfig config)
         {
-            var key = GetNewKey();
-
-            IWorker task;
-
-            switch (config.type)
+            lock (this)
             {
-                case "ApiClientAsync": task = new Worker_ApiClientAsync(config); break;
-                case "HttpClient": task = new Worker_HttpClient(config); break;
-                case "HttpUtil": task = new Worker_HttpUtil(config); break;
-                default: config.type = "ApiClient"; task = new Worker_ApiClient(config); break;
-            }
-
-            task.id = key;
-            return tasks.TryAdd(key, task);
+                var id = 1;
+
+                if (tasks.Count != 0)
+                {
+                    id = tasks.Keys.Max() + 1;
+                }
+
+                TaskItem taskItem = new TaskItem { config = config, id = id };
+
+                if (!tasks.TryAdd(id, taskItem))
+                {
+                    return false;
+                }
+
+                if (config.autoStart)
+                {
+                    MainTask.AddTask(() =>
+                    {
+                        taskItem.worker.Start();
+                    });
+                }
+                TaskMngSaveToCache();
+                return true;
+            }                     
         }
         public bool Start(int id)
         {
-            if (tasks.TryGetValue(id, out var task))
+            if (tasks.TryGetValue(id, out var taskItem))
             {
-                task.Start();
+                MainTask.AddTask(() =>
+                {
+                    taskItem.worker.Start();
+                });           
                 return true;
             }
             return false;
@@ -83,7 +109,7 @@ namespace App.Robot.Station.Logical
         {
             if (tasks.TryGetValue(id, out var task))
             {
-                task.Stop();
+                task.worker.Stop();
                 return true;
             }
             return false;
@@ -93,15 +119,18 @@ namespace App.Robot.Station.Logical
         {
             if (tasks.TryGetValue(id, out var task))
             {
-                task.Stop();
+                task.worker.Stop();
                 tasks.TryRemove(id, out _);
+
+                TaskMngSaveToCache();
+
                 return true;
             }
             return false;             
         }
 
 
-        public  List<IWorker> GetAll()
+        public  List<TaskItem> GetAll()
         {
             return tasks.Values.ToList();
         }

+ 5 - 2
dotnet/ServiceStation/Demo/StressTest/App.Robot.Station/Logical/Worker/IWorker.cs

@@ -6,9 +6,12 @@ namespace App.Robot.Station.Logical.Worker
 {
     public interface IWorker
     {
-        int id { get; set; }
+        int RunningThreadCount { get; }
 
-        TaskConfig config { get;  }
+        bool IsRunning { get; }
+
+
+        //TaskConfig config { get;  }
 
         void Start();
 

+ 23 - 39
dotnet/ServiceStation/Demo/StressTest/App.Robot.Station/Logical/Worker/Worker_ApiClient.cs

@@ -14,19 +14,24 @@ namespace App.Robot.Station.Logical.Worker
 
     public class Worker_ApiClient: IWorker
     {
-        public Worker_ApiClient(TaskConfig config)
+        [JsonIgnore]
+        protected TaskItem taskItem;
+
+        public Worker_ApiClient(TaskItem taskItem)
         {
-            this.config = config;
+            this.taskItem = taskItem;
+ 
 
-            tasks.threadCount = config.threadCount;
-            tasks.repeatCountPerThread = config.loopCountPerThread;
+            tasks.threadCount = taskItem.config.threadCount;
+            tasks.repeatCountPerThread = taskItem.config.loopCountPerThread;
 
             tasks.action = Processor;
         }
 
 
-        public string name => config.name;
-        public int id { get; set; }
+  
+
+
 
         [JsonIgnore]
         RepeatTaskHelp tasks = new RepeatTaskHelp();
@@ -36,29 +41,7 @@ namespace App.Robot.Station.Logical.Worker
 
         public bool IsRunning => tasks.IsRunning;
  
-        public long targetCount => config.threadCount * config.loopCountPerThread;
-
-        public long sumCount = 0;
-        public long sumFailCount = 0;
-
-        public long curCount =0;
-        public long failCount =0;
-        public TaskConfig config { get; set; }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        protected void StepUp(bool success)
-        {
-            Interlocked.Increment(ref curCount);
-            Interlocked.Increment(ref sumCount);
-            if (!success)
-            {
-                Interlocked.Increment(ref sumFailCount);
-                Interlocked.Increment(ref failCount);
-            }
-
-        }
-
-      
+  
     
 
 
@@ -69,33 +52,34 @@ namespace App.Robot.Station.Logical.Worker
             try
             {
                 
-                var ret = ApiClient.CallRemoteApi<ApiReturn>(config.apiRoute, config.apiArg, config.httpMethod);
+                var ret = ApiClient.CallRemoteApi<ApiReturn>(taskItem.config.apiRoute, taskItem.config.apiArg, taskItem.config.httpMethod);
                 if (ret == null || ret.success)
                 {
                     success = true;
                 }
                 else
                 {
-                    if(config.logError)
+                    if(taskItem.config.logError)
                     Logger.Info("失败:ret:" + ret.Serialize());
                 }
             }
             catch (Exception ex)
-            {
-                Interlocked.Increment(ref failCount);
+            {               
                 Logger.Error(ex);
             }
-            StepUp(success);
-            if(config.interval>0)
-                Thread.Sleep(config.interval);
+
+            taskItem.StepUp(success);
+
+            if (taskItem.config.interval > 0)
+                Thread.Sleep(taskItem.config.interval);
         }
 
         public void Start()
         {
-            tasks.threadName = "Robot-"+ config.name;
+            tasks.threadName = "Robot-"+ taskItem.config.name;
 
-            curCount = 0;
-            failCount = 0;
+            taskItem.curCount = 0;
+            taskItem.failCount = 0;
             tasks.Start();
         }
 

+ 36 - 47
dotnet/ServiceStation/Demo/StressTest/App.Robot.Station/Logical/Worker/Worker_ApiClientAsync.cs

@@ -1,5 +1,6 @@
 using System.Runtime.CompilerServices;
 using System.Threading;
+using Newtonsoft.Json;
 using Sers.Core.Module.Api;
 using Vit.Core.Module.Log;
 using Vit.Core.Util.ComponentModel.Data;
@@ -11,53 +12,34 @@ namespace App.Robot.Station.Logical.Worker
 
     public class Worker_ApiClientAsync: IWorker
     {
-        public Worker_ApiClientAsync(TaskConfig config)
+        [JsonIgnore]
+        protected TaskItem taskItem;
+
+        public Worker_ApiClientAsync(TaskItem taskItem)
         {
-            this.config = config;
+            this.taskItem = taskItem;
 
-            targetCount= config.threadCount * config.loopCountPerThread;
+            interval = taskItem.config.interval;
+            logError = taskItem.config.logError;
+            apiRoute = taskItem.config.apiRoute;
+            apiArg = taskItem.config.apiArg;      
+            httpMethod = taskItem.config.httpMethod;
         }
 
 
-        public string name => config.name;
-        public int id { get; set; }
-
-
-
-        public long RunningThreadCount = 0;
+        public bool IsRunning => runningThreadCount > 0;
+        public int RunningThreadCount => runningThreadCount;
 
 
+        int runningThreadCount = 0;
         bool needRunning = false;
 
-        public bool IsRunning => RunningThreadCount>0;
- 
-        public long targetCount;
-
-        public long sumCount = 0;
-        public long sumFailCount = 0;
-
-        public long curCount =0;
-        public long failCount =0;
-        public TaskConfig config { get; }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        protected void StepUp(bool success)
-        {          
-            Interlocked.Increment(ref curCount);
-            if (Interlocked.Increment(ref sumCount) >= targetCount) 
-            {
-                needRunning = false;
-            }
-            if (!success)
-            {
-                Interlocked.Increment(ref sumFailCount);
-                Interlocked.Increment(ref failCount);
-            }         
-        }
-
-      
-    
 
+        int interval;
+        bool logError;
+        string apiRoute;
+        string apiArg;
+        string httpMethod;
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         protected  void CallApi()
@@ -71,22 +53,28 @@ namespace App.Robot.Station.Logical.Worker
                 }
                 else
                 {
-                    if (config.logError)
+                    if (logError)
                         Logger.Info("失败:ret:" + ret.Serialize());
                 }
 
-                StepUp(success);
+                taskItem.StepUp(success);
+
+                if (taskItem.sumCount >= taskItem.targetCount)
+                {
+                    needRunning = false;
+                }
 
-                if (config.interval > 0)
-                    Thread.Sleep(config.interval);
+
+                if (interval > 0)
+                    Thread.Sleep(interval);
 
                 if (needRunning) CallApi();
                 else
                 {
-                    Interlocked.Decrement(ref RunningThreadCount);
+                    Interlocked.Decrement(ref runningThreadCount);
                 }
 
-            },config.apiRoute, config.apiArg, config.httpMethod);      
+            }, apiRoute,apiArg, httpMethod);      
           
         }
 
@@ -94,13 +82,14 @@ namespace App.Robot.Station.Logical.Worker
         {
             if (needRunning) return;
 
-            curCount = 0;
-            failCount = 0;
+            taskItem.curCount = 0;
+            taskItem.failCount = 0;
+
             needRunning = true;
 
-            for (var t = 0; t < config.threadCount; t++) 
+            for (var t = 0; t < taskItem.config.threadCount; t++) 
             {
-                Interlocked.Increment(ref RunningThreadCount);
+                Interlocked.Increment(ref runningThreadCount);
                 CallApi();
             }
         }

+ 14 - 12
dotnet/ServiceStation/Demo/StressTest/App.Robot.Station/Logical/Worker/Worker_HttpClient.cs

@@ -5,6 +5,7 @@ using Vit.Core.Module.Log;
 using Vit.Core.Util.ComponentModel.Data;
 using Vit.Extensions;
 using Vit.Core.Util.Net;
+using Newtonsoft.Json;
 
 namespace App.Robot.Station.Logical.Worker
 {
@@ -15,14 +16,14 @@ namespace App.Robot.Station.Logical.Worker
 
         HttpClient httpClient;
         HttpRequest httpClient_ReqParam;
-        public Worker_HttpClient(TaskConfig config):base(config)
+        public Worker_HttpClient(TaskItem taskItem) :base(taskItem)
         {
             httpClient = new HttpClient();
             httpClient_ReqParam = new HttpRequest
             {
-                url = config.apiRoute,
-                body = config.apiArg,
-                httpMethod = config.httpMethod
+                url = taskItem.config.apiRoute,
+                body = taskItem.config.apiArg,
+                httpMethod = taskItem.config.httpMethod
             };
 
         }
@@ -34,28 +35,29 @@ namespace App.Robot.Station.Logical.Worker
             bool success = false;
             try
             {
-
                 var ret = httpClient.Send<ApiReturn>(httpClient_ReqParam)?.data;
-                if (ret.success)
+                if (ret == null || ret.success)
                 {
                     success = true;
                 }
                 else
                 {
-                    if (config.logError)
+                    if (taskItem.config.logError)
                         Logger.Info("失败:ret:" + ret.Serialize());
                 }
             }
             catch (Exception ex)
-            {
-                Interlocked.Increment(ref failCount);
+            {       
                 Logger.Error(ex);
             }
-            StepUp(success);
-            Thread.Sleep(config.interval);
+
+            taskItem.StepUp(success);
+
+            if (taskItem.config.interval > 0)
+                Thread.Sleep(taskItem.config.interval);
         }
 
-        
+
 
     }
 }

+ 14 - 10
dotnet/ServiceStation/Demo/StressTest/App.Robot.Station/Logical/Worker/Worker_HttpUtil.cs

@@ -11,18 +11,19 @@ namespace App.Robot.Station.Logical.Worker
 
 
     public class Worker_HttpUtil : Worker_ApiClient
-    {
+    {       
 
         HttpUtil httpUtil;
         RequestParam httpUtil_Request;
-        public Worker_HttpUtil(TaskConfig config) : base(config)
+        public Worker_HttpUtil(TaskItem taskItem) : base(taskItem)
         {
+
             httpUtil = new HttpUtil();
             httpUtil_Request = new RequestParam
             {
-                url = config.apiRoute,
-                body = config.apiArg,
-                Method = config.httpMethod
+                url = taskItem.config.apiRoute,
+                body = taskItem.config.apiArg,
+                Method = taskItem.config.httpMethod
             };
         }
 
@@ -34,23 +35,26 @@ namespace App.Robot.Station.Logical.Worker
             try
             {
                 var ret = httpUtil.Ajax<ApiReturn>(httpUtil_Request);
-                if (ret.success)
+                if (ret == null || ret.success)
                 {
                     success = true;
                 }
                 else
                 {
-                    if (config.logError)
+                    if (taskItem.config.logError)
                         Logger.Info("失败:ret:" + ret.Serialize());
                 }
             }
             catch (Exception ex)
             {
-                Interlocked.Increment(ref failCount);
+               
                 Logger.Error(ex);
             }
-            StepUp(success);
-            Thread.Sleep(config.interval);
+
+            taskItem.StepUp(success);
+
+            if (taskItem.config.interval > 0)
+                Thread.Sleep(taskItem.config.interval);
         }
 
 

+ 2 - 2
dotnet/ServiceStation/Demo/StressTest/App.Robot.Station/wwwroot/_robot_/TaskMng.html

@@ -27,7 +27,7 @@
     <div id="items">
 
         <div v-for="item in items" style="width:300px;height:400px; float:left;margin:2px;padding:4px;word-wrap:break-word;" class="line">
-            {{item.id}}-{{item.name}}    <br />
+            [{{item.config.type}}] {{item.id}}-{{item.config.name}}    <br />
             sumCount:{{item.sumCount}}     <br />
             sumFailCount:{{item.sumFailCount}}     <br />
             curCount:{{item.curCount}}     <br />
@@ -107,7 +107,7 @@
         var config = new Vue({
             el: '#txtTaskConfig',
             data: {
-                config: '{"type":"ApiClientAsync","name": "Demo32","apiRoute": "/a", "threadCount": 32,"interval": 0, "autoStart": false,"loopCountPerThread": 1000000000, "//type":"ApiClient、ApiClientAsync、 HttpClient、HttpUtil","//apiRoute": "/demo/v1/api/333/arg", "//httpMethod":"GET","//apiArg": "{\\"Name\\":\\"lith\\"}" }'
+                config: '{"type":"ApiClientAsync","name": "Async","apiRoute": "/a", "threadCount": 8,"interval": 0, "autoStart": false,"loopCountPerThread": 1000000000, "//type":"ApiClient、ApiClientAsync、 HttpClient、HttpUtil","//apiRoute": "/demo/v1/api/333/arg", "//httpMethod":"GET","//apiArg": "{\\"Name\\":\\"lith\\"}" }'
             }
         });