C#数据库阻塞线程对大量客户端不利

时间:2017-01-26 19:24:22

标签: c# mysql multithreading sockets threadpool

的信息:

我为商务创建了一个C#控制台服务器和WinForms客户端。

(纠正我,如果我错了,我做了很多的研究。所以我可能会混淆某些话题。)

在服务器上,我已经了解到使用Socket.BegingReceive方法最好使用AsyncCallback。由于它使用ThreadPool类。多线程客户端同时还重用线程等(而不是在单线程设置或每个客户端的线程上进行while循环。(我已经读过这些具有特定的缺点,我不感兴趣。)) p>

基本上我所追求的是确保如果我正在制作的应用程序突然爆炸并且10万(甚至1,000,000?!)人们同时使用它,它将为每个客户保持良好和稳定的连接

情况:

服务器: Intel i5 4 Core:服务器处理另一台服务器上的MYSQL请求并将其提供给格式化的客户端他们会期待的。

客户端: 无限制的硬件资源:在浏览表单时要求服务器提供数据以填写表单。

所以我担心:让我们说4个客户端连接并请求服务器进程数据,大约需要5秒钟来处理MYSQL数据库(我知道,这就像处理速度的生命周期一样)。 (最糟糕的情况等))。如果第五个客户连接怎么办?这意味着ThreadPool必须创建另一个线程来保存此进程。现在让这些数字更大,我有100个同时客户端请求确切的长期运行方法。在4核CPU上。所以现在ThreadPool花费了十几秒甚至更长的时间来创建所有这些新线程。

问题:

编辑:缩小问题范围:

如何为FindPrimeNumbers调用实现异步编程。 (该方法是搜索数据库(不同服务器上的MySQL,如果有帮助的话)。)

我该怎么做以防止这种情况发生?我如何使这更直观。如何防止大型负载可能产生糟糕的用户体验等等。

Sudo Code

FindPrimerNumber方法就像数据库调用一样。

class Program
{
    private static Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    private static List<Socket> clientSockets = new List<Socket>();
    private static CancellationTokenSource CancelSource = new CancellationTokenSource();
    private static CancellationToken CancelToken = CancelSource.Token;
    private const int BUFFER_SIZE = 2048;
    private const int PORT = 100;
    private static readonly byte[] buffer = new byte[BUFFER_SIZE];

    static void Main()
    {
        SetupServer();
        Console.ReadLine();
        CloseAllSockets();
    }

    private static void SetupServer()
    {
        serverSocket.Bind(new IPEndPoint(IPAddress.Any, PORT));
        serverSocket.Listen(0);
        serverSocket.BeginAccept(BeginAcceptCallback, null);
    }

    private static void CloseAllSockets()
    {
        foreach (Socket socket in clientSockets)
        {
            socket.Shutdown(SocketShutdown.Both);
            socket.Close();
        }

        serverSocket.Close();
    }

    private static void BeginAcceptCallback(IAsyncResult AR)
    {
        Socket socket = serverSocket.EndAccept(AR);
        clientSockets.Add(socket);
        socket.BeginReceive(buffer, 0, BUFFER_SIZE, SocketFlags.None, BeginReceiveCallback, socket);
        Console.WriteLine("Client connected!");
        serverSocket.BeginAccept(BeginAcceptCallback, null);
    }

    private static void BeginReceiveCallback(IAsyncResult AR)
    {
        Socket current = (Socket)AR.AsyncState;
        int receivedInt = current.EndReceive(AR);
        byte[] received = new byte[receivedInt];
        Array.Copy(buffer, received, receivedInt);

        current.BeginReceive(buffer, 0, BUFFER_SIZE, SocketFlags.None, BeginReceiveCallback, current);

        string text = Encoding.ASCII.GetString(received);
        int number = 0;
        if (text.ToLower() == "exit")
        {
            current.Shutdown(SocketShutdown.Both);
            current.Close();
            clientSockets.Remove(current);
            Console.WriteLine("Client Disconnected");
            return;
        }
        else if (int.TryParse(text, out number))
        {
            int num = FindPrimeNumber(number);
            byte[] data = Encoding.ASCII.GetBytes(num.ToString());
            current.Send(data);
            Console.WriteLine("Prime Number: "+num+" :Sent");
        }
        else
        {
            current.Send(Encoding.ASCII.GetBytes("Not a Command"));
        }
    }

    //VERY LONG CPU FUNCTION
    public static int FindPrimeNumber(int n)
    {
        //Connect to database (MySQL Database on a different server, if that makes a difference)
        //Send Query
        //Read Return
        return queryReturn()
    }
}

1 个答案:

答案 0 :(得分:2)

您运行线程这一事实并不意味着该线程必须在核心上消耗100%的时钟周期。启动诊断工具(进程查看器或其他东西)并查看计算机上的线程数:它将是数百个。然后查看总CPU消耗:它将接近零。绝大多数线程花费大部分时间做任何事情,只等待其他事情发生。

另一方面,如果在数据库服务器上执行的查询花费的时间长达5秒,则会遇到麻烦,因为这意味着您对它施加了太大的压力,因此无论并行化如何,整个系统都将受到影响。

这些都是非常基本的东西,所以如果你还没有掌握它,那么担心它是不合时宜和不切实际的。只需做你必须做的事情,然后担心性能。