在实现异步C#HTTP服务器时使用cpu 100%问题

时间:2015-09-27 15:22:02

标签: c# node.js http

我试图在NodeJs中使用C#实现http服务器。 在NodeJs中,我实现了异步http服务器,如下所示。

var config = require('./config'),
    cluster = require('cluster'),
    dgwLogger = require('./modules/dgwLogger'),
    healthChecker = require('./modules/healthChecker'),
    crashLogger = require('./modules/crashLogger');

module.exports = exports = getWorkerID = function() {
    return cluster.worker === null ? 0 : cluster.worker.id;
}

if (config.useCluster && cluster.isMaster) {
    var cpuNum;
    if (typeof config.useCluster === 'number')
        cpuNum = config.useCluster;
    else
        cpuNum = require('os').cpus().length;
    for (var i = 0; i < cpuNum; i++) {
        cluster.fork();
    }
    cluster.on('exit', function(worker, code, signal) {
        cluster.fork();
    });
} else {
    var express = require('express'),
        http = require('http'),
    var app = express();

    app.use(express.bodyParser());
    app.use(express.cookieParser());
    app.use(express.methodOverride());
    app.use(app.router);
    app.use(sendResJson);
    app.use(express.errorHandler());

    app.post("/auth/getPJCharacter", gameServer.getPJCharacter);
    app.post("/auth/addPJCharacter", gameServer.addPJCharacter);

    setTimeout(function() { 
        http.createServer(app).listen(config.pjoa.port, function() {
            checkHealth();
        });
    }, 1000);
}

代码根据cpu计数创建所有线程,express模块​​监听单个端口。每当有来自端口的请求时,集群就会自动向单独的线程发送请求。 我听说这种方法可以有效地处理多个请求。但是现在,我在客户端使用C#,所以我也希望使用服务器端语言作为C#,因为我做了一个人项目,并且在服务器之间使用不同的语言很难和客户。 以下代码是C#版本。

class Program{
        static void Main (string[] args){
            WebServerMain main = new WebServerMain ();
            main.Init ();
        }
    }
    public class WebServerMain{
        private static WebServerMain singleton;
        public static WebServerMain Instance{
            get{
                return singleton;
            }
        }
        const int MAX_WORKERS = 2;
        AsyncHttpServer[] threadList = new AsyncHttpServer[MAX_WORKERS];
        public MySqlTest SqlManager;
        public MemAccessor MemManager;
        public TGBaseData BaseData;
        public WebServerMain (){}
        public void Init(){
            singleton = this;
            SqlManager = new MySqlTest ();
            MemManager = new MemAccessor ();
            MemManager.Init ();
            BaseData = new TGBaseData ();
            BaseData.Load ();
            for (int i = 0; i < MAX_WORKERS; i++) {
                threadList [i] = new AsyncHttpServer ();
                threadList[i].ID = i;
            }                                 
            StartLoop ();
        }
        public void StartLoop(){
            HttpListener listener = new HttpListener ();
            listener.Prefixes.Add("http://*:8081/");
            listener.Start();
            Console.WriteLine ("Server Started at localHost");
            while (true) {
                HttpListenerContext context = listener.GetContext();
                AsyncHttpServer temp = GetLessWorkingThread ();
                temp.QueueRequest (context);
            }
        }
        AsyncHttpServer GetLessWorkingThread(){
            int index = 0;
            int min = 1000000000;
            for (int i = 0; i < threadList.Length; i++) {
                if (threadList [i].TotalProcessing < min) {
                    min = threadList [i].TotalProcessing;
                    index = i;
                }
            }
            return threadList [index];
        }
    }
public class AsyncHttpServer
    {
        public int ID;
        public int TotalProcessing;
        //Queue
        MarshalSyncContext curSyncContext;
        Queue<HttpListenerContext> contextQueue;
        Thread loopThread;
        Dictionary<int,HttpListenerContext> contextDic;
        Dictionary<string,ServiceTaskDelegate> serviceDic;

        public AsyncHttpServer (){
            contextDic = new Dictionary<int, HttpListenerContext> ();
            contextQueue = new Queue<HttpListenerContext> ();

            serviceDic = new Dictionary<string,ServiceTaskDelegate> ();
            MainLoginService.AddService (serviceDic);
            ThrowGameMainService.AddService (serviceDic);

            loopThread = new Thread (DoListeningWork);
            loopThread.Start ();
        }
        public void QueueRequest(HttpListenerContext context){
            TotalProcessing++;
            contextQueue.Enqueue (context);
        }
        void DoListeningWork(){
            curSyncContext = new MarshalSyncContext ();
            while (true) {
                if (contextQueue.Count > 0) {
                    HttpListenerContext context = contextQueue.Dequeue ();
//                  Console.WriteLine ("Context=" + context.GetType ().ToString ());
                    Task req = ProcessRequest (context);
                    contextDic.Add (req.Id, context);
                    req.ContinueWith (task => {
                        TotalProcessing--;
                        HttpListenerContext tempContext = contextDic[ task.Id ];
                        contextDic.Remove(task.Id);
                        if(task.IsFaulted == true){
                            task.Exception.Handle( exception =>{
                                Console.WriteLine(exception.Message);
                                Console.WriteLine(exception.StackTrace);
                                return true;
                            });
                            XElement temp = new XElement("Root",
                                new XElement("Err",Err.INTERNAL_ERROR));
                            WriteSimpleText(tempContext, temp.ToString());
                            tempContext.Response.Close();
                        }
                    });
                }
                curSyncContext.ProcessAwaitProcedures ();
                Thread.Sleep (1000);
            }
        }

在AsyncHttpServer类中,类生成单个线程并检查从WebServerMain循环给出的队列数据。但是在等待队列时,我使用while(true)等待队列,但是这使得该程序的结果在完整的CPU资源中运行。 (如果我设置4个多线程,那么它使用400%的CPU)。 每当有请求时我都尝试创建Task线程,但这会产生太多线程,所以我不得不使用这个方法。 有没有办法不使用完整的CPU? 或者这是实现像NodeJS http服务器一样的异步Http服务器的正确方法吗?

0 个答案:

没有答案