队列 = =

理解:

先进先出(食堂打饭,先来的先打饭,就能先从队伍里出去了)

基本知识:

9个数全部放入队列后,初始化队列如下:

head = 1;

tail = 10; (队列中已经有9个元素了,tail指向队尾的后一个位置)

这样初始化的原因是:我们这里引入了两个变量head和tail。head用来记录队列的队首(即第一位),tail用来记录队列的队尾(即最后一位)的下一个位置。为啥不用tail不直接记录队尾,却要记录队尾的下一个位呢?这是因为当队列中只剩下一个元素时,队首和队尾重合会带来一些麻烦。所以我们规定队首和队尾重合时,队列为空。

此时head(1)和tail(10)之间的数就是目前队列中“有效”的数。要想删除一个数的话,head ++就OK了,这样仍然可以保持head和tail之间的数为目前队列中“有效”的数。这样做虽然浪费了一个空间,却节省了大量的时间(算法题就是拿空间换时间),这是非常划算的。

写在前面:

队列是一种特殊的线性结构,它只允许在队列的首部(head)进行删除操作,这成为“出队”;

在队列的尾部(tail)进行插入操作,这称为“入队”;

当队列中没有元素时(即head = tail),成为“空队列

操作:

(1)在队首删除一个数的操作:((出队)(dequeue)

head ++;

(2)在队尾增加一个数(x)的操作:((入队)(enqueue)

q[tail] = x ;
tail ++; 

用处:

是学习广度优先搜索以及队列优化的Bellman-Ford最短路算法的核心数据结构。所以现在将队列的三个基本元素(一个数组,两个变量)封装为一个结构体类型,如下:

struct queue
{
	int data[N]; // 队列的主体,用来存储内容
	int head; // 队首
	int tail; // 队尾 
}; 

基本操作代码:

#include<bits/stdc++.h>

using namespace std;

int main()
{
	int i;
    int q[102] = {0,6,3,1,7,5,8,9,2,4},head,tail;
	//初始化队列 
	head = 1;
	tail = 10; //队列中已经有9个元素了,tail指向队尾的后一个位置 
	while(head < tail) // 当队列不为空的时候执行循环
	{
		//打印队首并将队首出队
		cout << q[head] << ' ';
		head ++;
		
		//先将新队首的数添加到队尾
		q[tail] = q[head];
		tail ++;
		//再将队首出队
		head ++; 
	}
	getchar();
	getchar(); 
    return 0;
}

分类:

1.普通队列:

// hh 表示队头,tt表示队尾 
int q[N], hh = 0, tt = -1;

//向队尾插入一个数
q[ ++ tt] = x;

// 从队头弹出一个数
hh ++;

//队头的值
q[hh];

//判断队列是否为空
if(hh <= tt)
{
	not empty
} 

2.循环队列

//hh 表示队头,tt表示队尾的后一个位置
int q[N], hh = 0, tt = 0;

// 向队尾插入一个数
q[tt ++] = x;
if(tt == N) tt = 0;

// 从队头弹出一个数
hh ++;
if(hh == N) hh = 0;

//队头的值
q[hh];

//判断队列是否为空
if(hh != tt)
{
	not empty
} 

3.单调队列

常见模型:找出滑动窗口的最大值/最小值+

模板:

int i;
int hh = 0, tt = -1;
for(i = 0;i < n;i ++)
{
	while(hh <= tt && check_out(q[hh])) hh++; // 判断队头是否滑出窗口
	while(hh <= tt && check(q[tt], i))  t --;
	q[ ++ tt] = i; 
}

题目:

题目1:(普通队列纯裸题)

实现一个队列,队列初始为空,支持四种操作:

  1. push x – 向队尾插入一个数 x
  1. pop – 从队头弹出一个数;
  2. empty – 判断队列是否为空;
  3. query – 查询队头元素。

现在要对队列进行 M个操作,其中的每个操作 3 和操作 4都要输出相应的结果。

输入格式

第一行包含整数 M,表示操作次数。接下来 M行,每行包含一个操作命令,操作命令为 push xpopemptyquery 中的一种。

输出格式

对于每个 emptyquery 操作都要输出一个查询结果,每个结果占一行。

其中,empty 操作的查询结果为 YESNOquery 操作的查询结果为一个整数,表示队头元素的值。

数据范围

1≤M≤100000,1≤x≤10^9,
 

输入样例:

10
push 6
empty
query
pop
empty
push 3
push 4
pop
query
push 6

输出样例:

NO
6
YES
4

AC代码1:(数组模拟)

#include<bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;

int q[N];
int hh = 0,tt = -1;

int main()
{
	cin.tie(0);
	cout.tie(0);
	ios::sync_with_stdio(false);
	
	int i;
	int m;
	cin >> m;
	
	while(m --)
	{
		string s;
		cin >>s;
		
        if(s == "push") 
		{
			int x;
			cin >> x;
			q[++ tt] = x;
		}
		
		if(s == "pop")  hh ++;
	    
		if(s == "empty")
		{
			if(hh <= tt)  cout << "NO" << endl;
			else  cout << "YES" << endl;
		}
		
		if(s == "query")  cout << q[hh] << endl;
	} 
	
	return 0;
}

AC代码2:(STL)

#include<bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;

queue< int >q;

int hh = 0,tt = -1;

int main()
{
	cin.tie(0);
	cout.tie(0);
	ios::sync_with_stdio(false);
	
	int i;
	int m;
	cin >> m;
	
	while(m --)
	{
		string s;
		cin >>s;
		
        if(s == "push") 
		{
		    int x;
		    cin >> x;
		    q.push(x); // push函数:在队尾插入元素 
		}
		
		if(s == "pop")  q.pop(); // pop函数:弹出队头元素 
	    
		if(s == "empty") 
		{
			if(q.empty())  cout << "YES" << endl; // empty函数:查询队列是否为空,空返回是,不空返回否
			else  cout << "NO" << endl;
		}
		
		if(s == "query")  cout << q.front() << endl; // front函数:查询队头元素 
	} 
	
	return 0;
}

题目2:(单调队列纯裸题)

题目描述:

给定一个大小为 n≤106的数组。有一个大小为 k的滑动窗口,它从数组的最左边移动到最右边。只能在窗口中看到 k个数字。每次滑动窗口向右移动一个位置。以下是一个例子:该数组为 [1 3 -1 -3 5 3 6 7],k为 3。

窗口位置最小值最大值
[1 3 -1] -3 5 3 6 7-13
1 [3 -1 -3] 5 3 6 7-33
1 3 [-1 -3 5] 3 6 7-35
1 3 -1 [-3 5 3] 6 7-35
1 3 -1 -3 [5 3 6] 736
1 3 -1 -3 5 [3 6 7]37

你的任务是确定滑动窗口位于每个位置时,窗口中的最大值和最小值。

输入格式

输入包含两行。第一行包含两个整数 n和 k,分别代表数组长度和滑动窗口的长度。第二行有 n数,代表数组的具体数值。同行数据之间用空格隔开。

输出格式

输出包含两个。

第一行输出,从左至右,每个位置滑动窗口中的最小值。

第二行输出,从左至右,每个位置滑动窗口中的最大值。

输入样例:

8 3
1 3 -1 -3 5 3 6 7

输出样例:

-1 -3 -3 -3 3 3
3 3 5 5 6 7

AC代码:

#include<bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;

int a[N],q[N];// a数组存数字   q数组存下标 

int main()
{
	cin.tie(0);
	cout.tie(0);
	ios::sync_with_stdio(false);
	
	int i;
	int n,k;
	cin >> n >> k;
	for(i = 0 ; i < n ; i ++)  cin >> a[i];
	
	//输出每个区间的最小值 
	int hh = 0,tt = -1;
	
	//枚举每一个元素 
	for(i = 0 ; i < n ; i ++)
	{
		//判断队头是否已经滑出窗口
		if(hh <= tt && i - k + 1 > q[hh])  hh ++; // 队列不为空且当前区间的第一个数(i是当前区间最后一个数)的下标 > 队头,说明已经出队,所以队头要向后移动一位 
		
		while(hh <= tt && a[q[tt]] >= a[i]) tt--; // 队列不为空且新插入的数a[i]小于队尾,因为我们要输出最小值,那么队尾就没有用了,要把队尾删掉q数组队尾元素出队 
		
		q[++ tt] = i; // 把数a[i]的下标存到q数组里面去,此语句在if的上面的原因是,如果数a[i]很小,我们要保证输出当前的a[i];
		
		if(i >= k - 1)  cout << a[q[hh]] << ' '; //当前数足k个才输出,不足k个就不用输出了,这是题目要求 ,而且a[q数组]是单增的,输出队头就是当前区间的最小值 
	}
	cout << endl;
	
	//最大值同理,但是a[q数组要单减].
	int hh = 0,tt = -1; //一定要重置 
	
	//枚举每一个元素 
	for(i = 0 ; i < n ; i ++)
	{
		//判断队头是否已经滑出窗口
		if(hh <= tt && i - k + 1 > q[hh])  hh ++; 
		
		while(hh <= tt && a[q[tt]] <= a[i]) tt--; // 变号 
		
		q[++ tt] = i; 
		
		if(i >= k - 1)  cout << a[q[hh]] << ' ';
	}
	cout << endl;
	 
	
	return 0;
}

题目3:(单调队列+前缀和)

题目描述:

输入一个长度为n的整数序列,从中找出一段不超过m的连续子序列,使得整个序列的和最大。
例如 1,-3,5,1,-2,3
当m=4时,S=5+1-2+3=7
当m=2或m=3时,S=5+1=6

输入描述:

第一行两个数n,m(n,m≤300000)
第二行有n个数,要求在n个数找到最大子序和

输出描述:

一个数,数出他们的最大子序和

示例1:

输入:

6 4

1 -3 5 1 -2 3

输出:

7

考点:

单调队列


分析:
看到区间二字,我们首先想到前缀和数组,将原序列转化为前缀和数组后,我们要求的一段序列和,也就成了前缀和数组S[i]在[l,r]上的和,即s[r]-s[l-1];
也就是说,我们要在前缀和数组上找到两个点x,y,使得s[x]-s[y]最大,并且x-y<=m。
但又有一个问题,如果我们直接暴力枚举x,y,那必然超时,这个时候队列的作用就体现了,我们可以先固定右端点i,再去寻找一个左端点j,使得s[j]值最小,并且我们还可以确定j的范围[i-m,i-1],然后自己手捏数据找规律,我们可以发现 最优决策集合一定是一个下标位置递增,对应前缀和数组值也递增的序列。

AC代码:

#include<bits/stdc++.h>
 
using namespace std;
 
const int N = 3e5 + 10;
int q[N],s[N];

int main()
{
	int i;
    int n,m;
    int ans = 0;
    cin >> n >> m;
    for(i = 1 ; i <= n ; i ++)
    {
    	cin >> s[i];
    	s[i] = s[i] + s[i - 1]; // 前缀和 
	}
	int hh = 0,tt = 0;
	for(i = 1 ; i <= n ; i ++)
	{
		if(hh <= tt && i - m > q[hh])  hh ++; // 区间长度大于m,出队 
		ans = max(ans,s[i] - s[q[hh]]); // 寻找最优解
		while(hh <= tt && s[q[tt]] >= s[i])  tt --; // 若队尾不满足单调递增,出队
		q[++ tt] = i; // 把i当新的决策点 
	}
	cout << ans << endl; 
    return 0;
}

题目4:(队列)

题目描述:

题目描述:
有n个小组要排成一个队列,每个小组中有若干人。
当一个人来到队列时,如果队列中已经有了自己小组的成员,他就直接插队排在自己小组成员的后面,否则就站在队伍的最后面。
请你编写一个程序,模拟这种小组队列。


输入格式:
输入将包含一个或多个测试用例。
对于每个测试用例,第一行输入小组数量t。
接下来t行,每行输入一个小组描述,第一个数表示这个小组的人数,接下来的数表示这个小组的人的编号。
编号是0到999999范围内的整数。
一个小组最多可包含1000个人。
最后,命令列表如下。 有三种不同的命令:
1、ENQUEUE x - 将编号是x的人插入队列;
2、DEQUEUE - 让整个队列的第一个人出队;
3、STOP - 测试用例结束
每个命令占一行。
当输入用例t=0时,代表停止输入。
需注意:测试用例最多可包含200000(20万)个命令,因此小组队列的实现应该是高效的:
入队和出队都需要使用常数时间。


输出样例
对于每个测试用例,首先输出一行“Scenario #k”,其中k是测试用例的编号。
然后,对于每个DEQUEUE命令,输出出队的人的编号,每个编号占一行。
在每个测试用例(包括最后一个测试用例)输出完成后,输出一个空行。


数据范围
1≤t≤1000

样例1:

输入:

2

3 101 102 103

3 201 202 203

ENQUEUE 101

ENQUEUE 201

ENQUEUE 102

ENQUEUE 202

ENQUEUE 103

ENQUEUE 203

DEQUEUE

DEQUEUE

DEQUEUE

DEQUEUE

DEQUEUE

DEQUEUE

STOP

2

5 259001 259002 259003 259004 259005

6 260001 260002 260003 260004 260005 260006

ENQUEUE 259001

ENQUEUE 260001

ENQUEUE 259002

ENQUEUE 259003

ENQUEUE 259004

ENQUEUE 259005

DEQUEUE

DEQUEUE

ENQUEUE 260002

ENQUEUE 260003

DEQUEUE

DEQUEUE

DEQUEUE

DEQUEUE

STOP

0

输出:

Scenario #1

101

102

103

201

202

203

Scenario #2

259001

259002

259003

259004

259005

260001

AC代码:

#include<bits/stdc++.h>

using namespace std;

const int N = 1005;

queue<int> q[N],tq;
map <int,int> team;

int main()
{
	int i,t;
    int k=0;
    while(cin >> t && t != 0)
    {
        cout << "Scenario #" << ++ k << endl;
        while(!tq.empty())  tq.pop();
        team.clear();
        for(i = 0 ; i < N ; i++)  while(!q[i].empty())  q[i].pop(); // //初始化
        for(i = 0 ; i < t ; i ++)
        {
            int n,x;
            cin>>n;
            while(n --)
            {
                scanf("%d",&x);
                team[x]=i;//使用map将同一组数据映射到同一个i,i代表这个数据的组别
            }
        }
        string s;
        while(cin>>s)
        {
            int v;
            if(s=="STOP")  break;
            if(s=="ENQUEUE")
            {
                scanf("%d",&v);
                int i = team[v];//查询这个元素的组别
                if(q[i].empty())   tq.push(i);//如果当前组内没有元素被enqueue,就在teamqueue中插入这个组
                q[i].push(v);
            }
            else
            {
                if(q[tq.front()].size()==1)
                {
                    cout << q[tq.front()].front() << endl;
                    q[tq.front()].pop();
                    tq.pop();//如果这个组中所有插入的元素都将要被dequeue,就在teamqueue中pop这个组
                }
                else
                {
                    cout << q[tq.front()].front() << endl;
                    q[tq.front()].pop();
                }
            }
        }
        cout << endl;
    }
}

 

【以下是World.cs类中的 数据列队处理的代码内容 】 public static void MonitorDatabaseQueue() { try { int currentCount = SqlPool.Count; DateTime now = DateTime.Now; if ((now - lastMonitorTime).TotalSeconds >= 5) { processingSpeed = (lastQueueCount - currentCount) / 5; lastQueueCount = currentCount; lastMonitorTime = now; Form1.WriteLine(1, $"数据库队列监控: 当前队列={currentCount}, 处理速度={processingSpeed}/秒"); } if (currentCount > 1000 && processingSpeed > 0) { int requiredThreads = Math.Min(Environment.ProcessorCount * 2, (currentCount / 500) + 1); } } catch (Exception ex) { Form1.WriteLine(1, "队列监控出错: " + ex.ToString()); } } public static void ProcessSqlQueue() { var connectionCache = new Dictionary<string, SqlConnection>(); try { const int maxRetry = 3; const int maxProcessPerCycle = 5000; const int batchSize = 50; int processedCount = 0; var batchList = new List<DbPoolClass>(batchSize); while (processedCount < maxProcessPerCycle) { while (batchList.Count < batchSize && processedCount < maxProcessPerCycle && SqlPool.TryDequeue(out DbPoolClass item)) { batchList.Add(item); processedCount++; } if (batchList.Count == 0) { break; } try { foreach (var group in batchList.GroupBy(x => x.Conn)) { SqlConnection conn = null; try { if (!connectionCache.TryGetValue(group.Key, out conn) || conn.State != ConnectionState.Open) { conn = new SqlConnection(group.Key); conn.Open(); connectionCache[group.Key] = conn; } foreach (var item in group) { int result = DbPoolClass.DbPoolClassRun(conn, item.Sql, item.Prams, item.Type); if (result == -1 && item.RetryCount < maxRetry) { item.RetryCount++; SqlPool.Enqueue(item); } } } catch (Exception ex) { Form1.WriteLine(1, $"分组执行出错: {ex.Message}"); SafeCloseConnection(conn, group.Key, connectionCache); foreach (var item in group) { if (item.RetryCount < maxRetry) { item.RetryCount++; SqlPool.Enqueue(item); } } } } } catch (Exception ex) { Form1.WriteLine(1, $"批量处理出错: {ex.Message}"); foreach (var item in batchList) { if (item.RetryCount < maxRetry) { item.RetryCount++; SqlPool.Enqueue(item); } } } batchList.Clear(); if (SqlPool.Count > 1000) { Thread.Sleep(Math.Min(50, SqlPool.Count / 200)); } } } finally { foreach (var conn in connectionCache.Values) { SafeCloseConnection(conn); } } } private static void SafeCloseConnection(SqlConnection conn, string key = null, Dictionary<string, SqlConnection> cache = null) { try { if (conn?.State == ConnectionState.Open) conn.Close(); if (key != null && cache != null) cache.Remove(key); } catch { } } 【以上是 World.cs类的数据库列队处理代码内容】 【以下是 DbPoolClass.cs类全部代码内容】 using System; using System.Collections.Concurrent; using System.Data; using System.Data.SqlClient; using System.Threading; using System.Threading.Tasks; namespace RxjhServer.DbClss { public class DbPoolClass { private string _Conn; private SqlParameter[] _Prams; private int _Type; private string _Sql; public int _RetryCount; public string Conn { get { return _Conn; } set { _Conn = value; } } public SqlParameter[] Prams { get { return _Prams; } set { _Prams = value; } } public int Type { get { return _Type; } set { _Type = value; } } public int RetryCount { get { return _RetryCount; } set { _RetryCount = value; } } public string Sql { get { return _Sql; } set { _Sql = value; } } public static int DbPoolClassRun(SqlConnection conn, string procName, SqlParameter[] prams, int Type) { try { if (conn == null || conn.State != ConnectionState.Open) { Form1.WriteLine(1, $"[SQL错误] 连接不可用:{procName}"); return -1; } //Form1.WriteLine(1, $"[SQL执行] 数据库:{conn.Database} 开始执行:{procName}"); int result; if (Type == 1) { result = SqlDBA.RunProcSql(conn, procName, prams); } else { result = SqlDBA.RunProc(conn, procName, prams); } //Form1.WriteLine(1, $"[SQL完成] 数据库:{conn.Database} 执行成功:{procName}"); return result; } catch (SqlException sqlEx) { if (sqlEx.Number == 1205 || sqlEx.Number == -2) { Form1.WriteLine(1, $"DbPoolClassRun 致命错误[{sqlEx.Number}]:{procName}, 错误:{sqlEx.Message}"); return 0; } switch (sqlEx.Number) { case 53: case 233: Form1.WriteLine(1, $"DbPoolClassRun 连接错误[{sqlEx.Number}]:{procName}, 错误:{sqlEx.Message}"); Thread.Sleep(5000); return -1; default: Form1.WriteLine(1, $"DbPoolClassRun SQL错误[{sqlEx.Number}]:{procName}, 错误:{sqlEx.Message}"); return -1; } } catch (Exception ex) { Form1.WriteLine(1, $"DbPoolClassRun 常规错误:{procName}, 错误:{ex.Message}\n堆栈:{ex.StackTrace}"); return -1; } } private static string GetConnectionPoolStats(string connectionString) { try { var builder = new SqlConnectionStringBuilder(connectionString); using (var conn = new SqlConnection(builder.ConnectionString)) { var pool = typeof(SqlConnection).GetMethod("GetConnectionPoolCount", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); if (pool != null) { var counts = (int[])pool.Invoke(null, new object[] { builder.ConnectionString }); return $"池中连接数: {counts[0]}, 活动连接: {counts[1]}, 空闲连接: {counts[2]}"; } return "无法获取连接池信息"; } } catch { return "连接池状态获取失败"; } } } } 【以上是 DbPoolClass.cs类全部代码内容】 【以下是 SqlDBA.cs 类中全部代码内容】 using System; using System.Data; using System.Data.SqlClient; namespace RxjhServer.DbClss { public class SqlDBA { private static readonly object _connectionLock = new object(); public static int RunProc(SqlConnection conn, string procName, SqlParameter[] prams) { try { if (conn.State != ConnectionState.Open) { conn.Open(); } using (var cmd = CreateCommand(conn, procName, prams)) { cmd.ExecuteNonQuery(); return (int)cmd.Parameters["ReturnValue"].Value; } } catch (SqlException sqlEx) { Form1.WriteLine(100, $"SqlDBA数据层_存储过程错误 {procName}: {sqlEx.Number} - {sqlEx.Message}"); return -1; } catch (Exception ex) { Form1.WriteLine(100, $"SqlDBA数据层_错误1 {procName}: {ex.Message}"); return -1; } } public static int RunProcSql(SqlConnection conn, string procName, SqlParameter[] prams) { try { if (conn.State != ConnectionState.Open) { conn.Open(); } using (var cmd = CreateCommandSql(conn, procName, prams)) { return cmd.ExecuteNonQuery(); } } catch (SqlException sqlEx) { Form1.WriteLine(100, $"SqlDBA数据层_SQL错误 {procName}: {sqlEx.Number} - {sqlEx.Message}"); return -1; } catch (Exception ex) { Form1.WriteLine(100, $"SqlDBA数据层_错误2 {procName}: {ex.Message}"); return -1; } } public static SqlCommand CreateCommand(SqlConnection conn, string procName, SqlParameter[] prams) { if (conn == null) { throw new ArgumentNullException(nameof(conn)); } if (string.IsNullOrWhiteSpace(procName)) { throw new ArgumentException("Procedure name cannot be empty.", nameof(procName)); } var command = new SqlCommand(procName, conn) { CommandType = CommandType.StoredProcedure, CommandTimeout = 180 }; AddParametersToCommand(command, prams); return command; } public static SqlCommand CreateCommandSql(SqlConnection conn, string sqlQuery, SqlParameter[] prams) { if (conn == null) { throw new ArgumentNullException(nameof(conn)); } if (string.IsNullOrWhiteSpace(sqlQuery)) { throw new ArgumentException("SQL query cannot be empty.", nameof(sqlQuery)); } var command = new SqlCommand(sqlQuery, conn) { CommandType = CommandType.Text, CommandTimeout = 180 }; AddParametersToCommand(command, prams); return command; } private static void AddParametersToCommand(SqlCommand command, SqlParameter[] prams) { if (prams != null && prams.Length > 0) { command.Parameters.AddRange(prams); } command.Parameters.Add(new SqlParameter("ReturnValue", SqlDbType.Int) { Direction = ParameterDirection.ReturnValue }); } public static SqlParameter MakeInParam(string paramName, SqlDbType dbType, int size, object value) { return MakeParam(paramName, dbType, size, ParameterDirection.Input, value); } public static SqlParameter MakeParam(string paramName, SqlDbType dbType, int size, ParameterDirection direction, object value) { if (string.IsNullOrWhiteSpace(paramName)) { throw new ArgumentException("Parameter name cannot be empty.", nameof(paramName)); } var parameter = size > 0 ? new SqlParameter(paramName, dbType, size) : new SqlParameter(paramName, dbType); parameter.Direction = direction; if (direction != ParameterDirection.Output || value != null) { parameter.Value = value ?? DBNull.Value; } return parameter; } } } 【以上是 SqlDBA.cs 类中全部代码内容】 【以下是 DBA.cs 类中全部代码内容】 using System; using System.Collections; using System.Data; using System.Data.SqlClient; namespace RxjhServer.DbClss { public class DBA { public static void serlog(string txt) { string sqlJl = World.SqlJl; if (!(sqlJl != "")) { return; } string[] array = sqlJl.Split('|'); for (int i = 0; i < array.Length; i++) { if (txt.ToLower().IndexOf(array[i].ToLower()) != -1) { Form1.WriteLine(100, txt); } } } public static void serlog(string txt, SqlParameter[] prams) { string sqlJl = World.SqlJl; if (!(sqlJl != "")) { return; } string[] array = sqlJl.Split('|'); for (int i = 0; i < array.Length; i++) { if (txt.ToLower().IndexOf(array[i].ToLower()) != -1) { Form1.WriteLine(100, txt); } } for (int j = 0; j < array.Length; j++) { foreach (SqlParameter sqlParameter in prams) { if (sqlParameter.SqlValue.ToString().ToLower().IndexOf(array[j].ToLower()) != -1) { Form1.WriteLine(100, txt + " " + sqlParameter.SqlValue.ToString()); } } } } public static void Setlog(string txt, SqlParameter[] prams, Exception ex) { Form1.WriteLine(100, "-----------DBA数据层_错误-----------"); Form1.WriteLine(100, txt); if (prams != null) { foreach (SqlParameter sqlParameter in prams) { Form1.WriteLine(100, sqlParameter.SqlValue.ToString()); } } Form1.WriteLine(100, ex.Message); } public static string getstrConnection(string db) { try { if (db == null) { db = "GameServer"; } if (World.Db.TryGetValue(db, out var value)) { return value.SqlConnect; } return null; } catch { return null; } } public static int ExeSqlCommand(string sqlCommand, SqlParameter[] prams) { serlog(sqlCommand, prams); using SqlConnection sqlConnection = new SqlConnection(getstrConnection(null)); using SqlCommand sqlCommand2 = SqlDBA.CreateCommandSql(sqlConnection, sqlCommand, prams); int result = -1; try { sqlConnection.Open(); } catch { return -1; } try { result = sqlCommand2.ExecuteNonQuery(); } catch (Exception ex) { Setlog(sqlCommand, prams, ex); } sqlCommand2.Dispose(); sqlConnection.Close(); sqlConnection.Dispose(); return result; } public static int ExeSqlCommand(string sqlCommand, SqlParameter[] prams, string server) { serlog(sqlCommand, prams); using SqlConnection sqlConnection = new SqlConnection(getstrConnection(server)); using SqlCommand sqlCommand2 = SqlDBA.CreateCommandSql(sqlConnection, sqlCommand, prams); int result = -1; try { sqlConnection.Open(); } catch { return -1; } try { result = sqlCommand2.ExecuteNonQuery(); } catch (Exception ex) { Setlog(sqlCommand, prams, ex); } sqlCommand2.Dispose(); sqlConnection.Close(); sqlConnection.Dispose(); return result; } public static int ExeSqlCommand(string sqlCommand) { serlog(sqlCommand); using SqlConnection sqlConnection = new SqlConnection(getstrConnection(null)); using SqlCommand sqlCommand2 = new SqlCommand(sqlCommand, sqlConnection); int result = -1; try { sqlConnection.Open(); } catch { return -1; } try { result = sqlCommand2.ExecuteNonQuery(); } catch (Exception ex) { Setlog(sqlCommand, null, ex); } sqlCommand2.Dispose(); sqlConnection.Close(); sqlConnection.Dispose(); return result; } public static int ExeSqlCommand(string sqlCommand, string server) { serlog(sqlCommand); using SqlConnection sqlConnection = new SqlConnection(getstrConnection(server)); using SqlCommand sqlCommand2 = new SqlCommand(sqlCommand, sqlConnection); int result = -1; try { sqlConnection.Open(); } catch { return -1; } try { result = sqlCommand2.ExecuteNonQuery(); } catch (Exception ex) { Setlog(sqlCommand, null, ex); } sqlCommand2.Dispose(); sqlConnection.Close(); sqlConnection.Dispose(); return result; } public static int ExeSqlCommand(string sqlCommand, ref Exception exception, string db) { serlog(sqlCommand); using SqlConnection sqlConnection = new SqlConnection(getstrConnection(null)); using SqlCommand sqlCommand2 = new SqlCommand(sqlCommand, sqlConnection); try { sqlConnection.Open(); } catch (Exception ex) { Exception ex2 = (exception = ex); return -1; } int result = sqlCommand2.ExecuteNonQuery(); sqlCommand2.Dispose(); sqlConnection.Close(); sqlConnection.Dispose(); return result; } public static DateTime GetDateTime(string sql, string dbName) { string connectionString = getstrConnection(dbName); if (string.IsNullOrEmpty(connectionString)) { return DateTime.MinValue; } using (SqlConnection conn = new SqlConnection(connectionString)) { try { conn.Open(); using (SqlCommand cmd = new SqlCommand(sql, conn)) { object result = cmd.ExecuteScalar(); if (result != null && result != DBNull.Value) { return Convert.ToDateTime(result); } return DateTime.MinValue; } } catch { return DateTime.MinValue; } } } public static DataTable GetDBToDataTable(string sqlCommand, SqlParameter[] prams) { serlog(sqlCommand, prams); using SqlConnection sqlConnection = new SqlConnection(getstrConnection(null)); using SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(); SqlCommand sqlCommand3 = (sqlDataAdapter.SelectCommand = SqlDBA.CreateCommandSql(sqlConnection, sqlCommand, prams)); SqlCommand sqlCommand4 = sqlCommand3; using (sqlCommand4) { try { sqlConnection.Open(); } catch (Exception ex) { Form1.WriteLine(100, "DBA数据层_错误1" + ex.Message + " " + sqlCommand); return null; } DataTable dataTable = new DataTable(); try { sqlDataAdapter.Fill(dataTable); } catch (Exception ex2) { Setlog(sqlCommand, prams, ex2); } sqlDataAdapter.Dispose(); sqlConnection.Close(); sqlConnection.Dispose(); return dataTable; } } public static DataTable GetDBToDataTable(string sqlCommand, SqlParameter[] prams, string server) { serlog(sqlCommand, prams); using SqlConnection sqlConnection = new SqlConnection(getstrConnection(server)); using SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(); SqlCommand sqlCommand3 = (sqlDataAdapter.SelectCommand = SqlDBA.CreateCommandSql(sqlConnection, sqlCommand, prams)); SqlCommand sqlCommand4 = sqlCommand3; using (sqlCommand4) { try { sqlConnection.Open(); } catch (Exception ex) { Form1.WriteLine(100, "DBA数据层_错误2" + ex.Message + " " + sqlCommand); return null; } DataTable dataTable = new DataTable(); try { sqlDataAdapter.Fill(dataTable); } catch (Exception ex2) { Setlog(sqlCommand, prams, ex2); } sqlDataAdapter.Dispose(); sqlConnection.Close(); sqlConnection.Dispose(); return dataTable; } } public static DataTable GetDBToDataTable(string sqlCommand) { serlog(sqlCommand); using SqlConnection sqlConnection = new SqlConnection(getstrConnection(null)); using SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(); SqlCommand sqlCommand3 = (sqlDataAdapter.SelectCommand = new SqlCommand(sqlCommand, sqlConnection)); SqlCommand sqlCommand4 = sqlCommand3; using (sqlCommand4) { try { sqlConnection.Open(); } catch (Exception ex) { Form1.WriteLine(100, "DBA数据层_错误3" + ex.Message + " " + sqlCommand); return null; } DataTable dataTable = new DataTable(); try { sqlDataAdapter.Fill(dataTable); } catch (Exception ex2) { Setlog(sqlCommand, null, ex2); } sqlDataAdapter.Dispose(); sqlConnection.Close(); sqlConnection.Dispose(); return dataTable; } } public static DataTable GetDBToDataTable(string sqlCommand, string server) { serlog(sqlCommand); using SqlConnection sqlConnection = new SqlConnection(getstrConnection(server)); using SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(); SqlCommand sqlCommand3 = (sqlDataAdapter.SelectCommand = new SqlCommand(sqlCommand, sqlConnection)); SqlCommand sqlCommand4 = sqlCommand3; using (sqlCommand4) { try { sqlConnection.Open(); } catch { return null; } DataTable dataTable = new DataTable(); try { sqlDataAdapter.Fill(dataTable); } catch (Exception ex) { Setlog(sqlCommand, null, ex); } sqlDataAdapter.Dispose(); sqlConnection.Close(); sqlConnection.Dispose(); return dataTable; } } public static DataRowCollection smethod_0(string sqlCommand, string db) { return GetDBToDataTable(sqlCommand).Rows; } public static ArrayList GetDBValue_1(string sqlCommand, string db) { serlog(sqlCommand); using SqlConnection sqlConnection = new SqlConnection(getstrConnection(null)); using SqlCommand sqlCommand2 = new SqlCommand(sqlCommand, sqlConnection); try { sqlConnection.Open(); } catch { return null; } SqlDataReader sqlDataReader = sqlCommand2.ExecuteReader(); if (!sqlDataReader.HasRows) { sqlDataReader.Close(); sqlDataReader.Dispose(); sqlConnection.Close(); sqlConnection.Dispose(); return null; } ArrayList arrayList = new ArrayList(); if (sqlDataReader.Read()) { for (int i = 0; i < sqlDataReader.FieldCount; i++) { arrayList.Add(sqlDataReader[i]); } } sqlDataReader.Close(); sqlDataReader.Dispose(); sqlConnection.Close(); sqlConnection.Dispose(); return arrayList; } public static ArrayList GetDBValue_2(string sqlCommand, string db) { serlog(sqlCommand); using SqlConnection sqlConnection = new SqlConnection(getstrConnection(null)); using SqlCommand sqlCommand2 = new SqlCommand(sqlCommand, sqlConnection); try { sqlConnection.Open(); } catch { return null; } SqlDataReader sqlDataReader = sqlCommand2.ExecuteReader(); if (!sqlDataReader.HasRows) { sqlDataReader.Close(); sqlDataReader.Dispose(); sqlConnection.Close(); sqlConnection.Dispose(); return null; } ArrayList arrayList = new ArrayList(); while (sqlDataReader.Read()) { arrayList.Add(sqlDataReader[0]); } sqlDataReader.Close(); sqlDataReader.Dispose(); sqlConnection.Close(); sqlConnection.Dispose(); return arrayList; } public static object GetDBValue_3(string sqlCommand) { serlog(sqlCommand); object result = null; using SqlConnection sqlConnection = new SqlConnection(getstrConnection(null)); using SqlCommand sqlCommand2 = new SqlCommand(sqlCommand, sqlConnection); try { sqlConnection.Open(); } catch { return null; } try { result = sqlCommand2.ExecuteScalar(); } catch (Exception ex) { Form1.WriteLine(100, "DBA数据层_错误4" + ex.Message + " " + sqlCommand); } sqlCommand2.Dispose(); sqlConnection.Close(); sqlConnection.Dispose(); return result; } public static object GetDBValue_3(string sqlCommand, SqlParameter[] prams) { serlog(sqlCommand, prams); object result = null; using SqlConnection sqlConnection = new SqlConnection(getstrConnection(null)); using SqlCommand sqlCommand2 = SqlDBA.CreateCommandSql(sqlConnection, sqlCommand, prams); try { sqlConnection.Open(); } catch { return null; } try { result = sqlCommand2.ExecuteScalar(); } catch (Exception ex) { Form1.WriteLine(100, "DBA数据层_错误5" + ex.Message + " " + sqlCommand); } sqlCommand2.Dispose(); sqlConnection.Close(); sqlConnection.Dispose(); return result; } public static object GetDBValue_3(string sqlCommand, string db) { serlog(sqlCommand); object result = null; using SqlConnection sqlConnection = new SqlConnection(getstrConnection(db)); using SqlCommand sqlCommand2 = new SqlCommand(sqlCommand, sqlConnection); try { sqlConnection.Open(); } catch { return null; } try { result = sqlCommand2.ExecuteScalar(); } catch (Exception ex) { Form1.WriteLine(100, "DBA数据层_错误6" + ex.Message + " " + sqlCommand); } sqlCommand2.Dispose(); sqlConnection.Close(); sqlConnection.Dispose(); return result; } } } 【以上是 DBA.cs 类中全部代码内容】 数据库队列监控: 当前队列=1278, 处理速度=-255/秒 2025/6/24 16:48:54 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:48:54 数据库队列监控: 当前队列=1646, 处理速度=-73/秒 2025/6/24 16:49:02 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:49:02 数据库队列监控: 当前队列=1128, 处理速度=103/秒 2025/6/24 16:49:11 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:49:11 数据库队列监控: 当前队列=1501, 处理速度=-74/秒 2025/6/24 16:49:19 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:49:19 数据库队列监控: 当前队列=984, 处理速度=103/秒 2025/6/24 16:49:19 封包处理错误: 封包处理超时 2025/6/24 16:49:27 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:49:27 数据库队列监控: 当前队列=1372, 处理速度=-77/秒 2025/6/24 16:49:35 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:49:36 数据库队列监控: 当前队列=2027, 处理速度=-131/秒 2025/6/24 16:49:44 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:49:44 数据库队列监控: 当前队列=2163, 处理速度=-27/秒 2025/6/24 16:49:53 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:49:53 数据库队列监控: 当前队列=2558, 处理速度=-79/秒 2025/6/24 16:50:02 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:50:02 数据库队列监控: 当前队列=2949, 处理速度=-78/秒 2025/6/24 16:50:11 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:50:11 数据库队列监控: 当前队列=3341, 处理速度=-78/秒 2025/6/24 16:50:20 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:50:20 数据库队列监控: 当前队列=3730, 处理速度=-77/秒 2025/6/24 16:50:30 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:50:30 数据库队列监控: 当前队列=4113, 处理速度=-76/秒 2025/6/24 16:50:39 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:50:39 数据库队列监控: 当前队列=5404, 处理速度=-258/秒 2025/6/24 16:50:49 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:50:49 数据库队列监控: 当前队列=6695, 处理速度=-258/秒 2025/6/24 16:51:02 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:51:02 数据库队列监控: 当前队列=8892, 处理速度=-439/秒 2025/6/24 16:51:15 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:51:15 数据库队列监控: 当前队列=12004, 处理速度=-622/秒 2025/6/24 16:51:29 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:51:29 数据库队列监控: 当前队列=15627, 处理速度=-724/秒 2025/6/24 16:51:43 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:51:44 数据库队列监控: 当前队列=19847, 处理速度=-844/秒 2025/6/24 16:51:56 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:51:56 数据库队列监控: 当前队列=22235, 处理速度=-477/秒 2025/6/24 16:52:10 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:52:10 数据库队列监控: 当前队列=25479, 处理速度=-648/秒 2025/6/24 16:52:23 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:52:23 数据库队列监控: 当前队列=28448, 处理速度=-593/秒 2025/6/24 16:52:37 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:52:37 数据库队列监控: 当前队列=31561, 处理速度=-622/秒 2025/6/24 16:52:51 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:52:51 数据库队列监控: 当前队列=35604, 处理速度=-808/秒 2025/6/24 16:53:05 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:53:05 数据库队列监控: 当前队列=39570, 处理速度=-793/秒 2025/6/24 16:53:20 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:53:20 数据库队列监控: 当前队列=42944, 处理速度=-674/秒 2025/6/24 16:53:32 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:53:32 数据库队列监控: 当前队列=45219, 处理速度=-455/秒 2025/6/24 16:53:46 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:53:47 数据库队列监控: 当前队列=49989, 处理速度=-954/秒 2025/6/24 16:54:01 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:54:01 数据库队列监控: 当前队列=53102, 处理速度=-622/秒 2025/6/24 16:54:16 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:54:16 数据库队列监控: 当前队列=57119, 处理速度=-803/秒 2025/6/24 16:54:29 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:54:29 数据库队列监控: 当前队列=60229, 处理速度=-622/秒 2025/6/24 16:54:46 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:54:46 数据库队列监控: 当前队列=66041, 处理速度=-1162/秒 2025/6/24 16:55:00 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:55:00 数据库队列监控: 当前队列=69154, 处理速度=-622/秒 2025/6/24 16:55:14 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:55:14 数据库队列监控: 当前队列=72530, 处理速度=-675/秒 2025/6/24 16:55:27 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:55:27 数据库队列监控: 当前队列=75374, 处理速度=-568/秒 2025/6/24 16:55:41 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:55:42 数据库队列监控: 当前队列=79383, 处理速度=-801/秒 2025/6/24 16:55:59 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:55:59 数据库队列监控: 当前队列=85195, 处理速度=-1162/秒 2025/6/24 16:56:12 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:56:12 数据库队列监控: 当前队列=87402, 处理速度=-441/秒 2025/6/24 16:56:27 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:56:27 数据库队列监控: 当前队列=91412, 处理速度=-802/秒 2025/6/24 16:56:46 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:56:46 数据库队列监控: 当前队列=98127, 处理速度=-1343/秒 2025/6/24 16:57:02 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:57:02 数据库队列监控: 当前队列=103037, 处理速度=-982/秒 2025/6/24 16:57:19 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:57:19 数据库队列监控: 当前队列=107955, 处理速度=-983/秒 2025/6/24 16:57:34 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:57:34 数据库队列监控: 当前队列=111970, 处理速度=-803/秒 2025/6/24 16:57:52 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:57:53 数据库队列监控: 当前队列=118709, 处理速度=-1347/秒 2025/6/24 16:58:08 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:58:08 数据库队列监控: 当前队列=123743, 处理速度=-1006/秒 2025/6/24 16:58:32 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:58:32 数据库队列监控: 当前队列=132499, 处理速度=-1751/秒 2025/6/24 16:59:01 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:59:01 数据库队列监控: 当前队列=145462, 处理速度=-2592/秒 2025/6/24 16:59:08 封包处理错误: 封包处理超时 2025/6/24 16:59:22 网络队列: 连接数=302(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/24 16:59:22 数据库队列监控: 当前队列=153043, 处理速度=-1516/秒 2025/6/24 16:59:23 封包处理错误: 封包处理超时 2025/6/24 16:59:33 封包处理错误: 封包处理超时 2025/6/24 16:59:34 封包处理错误: 封包处理超时 上诉数据列队处理的代码垃圾的很,登录300个假人测试了40分钟数据列队直接飙升到55万,CPU使用直接飙升到100%,无法形容的垃圾代码 然后你给我优化了一下 新建了一个类 : using RxjhServer; using RxjhServer.DbClss; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Data; using System.Data.SqlClient; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace RxjhServer { public static class DatabaseQueueProcessor { private static DateTime lastMonitorTime = DateTime.MinValue; private static int lastQueueCount = 0; private static double processingSpeed = 0; private static int activeThreads = 0; private static readonly object threadLock = new object(); private static CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); public static void StartProcessing() { // 启动监控线程 Task.Run(() => MonitorDatabaseQueue()); // 初始启动4个处理线程 for (int i = 0; i < 4; i++) { StartNewProcessingThread(); } } public static void StopProcessing() { cancellationTokenSource.Cancel(); } private static void StartNewProcessingThread() { lock (threadLock) { if (activeThreads >= Environment.ProcessorCount * 4) return; activeThreads++; } Task.Run(() => { try { ProcessSqlQueue(cancellationTokenSource.Token); } finally { lock (threadLock) { activeThreads--; } } }); } public static void MonitorDatabaseQueue() { while (!cancellationTokenSource.IsCancellationRequested) { try { int currentCount = World.SqlPool.Count; DateTime now = DateTime.Now; // 每5秒计算一次处理速度 if ((now - lastMonitorTime).TotalSeconds >= 5) { int processedItems = lastQueueCount - currentCount; // 如果队列增长了,计算增长速率 if (processedItems < 0) { processingSpeed = -processedItems / 5; // 队列增长速率 } else { processingSpeed = processedItems / 5; // 处理速率 } lastQueueCount = currentCount; lastMonitorTime = now; Form1.WriteLine(1, $"数据库队列监控: 当前队列={currentCount}, 处理速度={(processedItems < 0 ? "-" : "")}{processingSpeed}/秒, 活动线程={activeThreads}"); // 动态调整线程数量 AdjustProcessingThreads(currentCount); } Thread.Sleep(1000); // 每秒检查一次 } catch (Exception ex) { Form1.WriteLine(1, "队列监控出错: " + ex.ToString()); Thread.Sleep(5000); } } } private static void AdjustProcessingThreads(int currentQueueSize) { if (currentQueueSize < 500) return; int desiredThreads; if (processingSpeed <= 0 || currentQueueSize / processingSpeed > 10) { // 队列在增长或处理速度不足 desiredThreads = Math.Min( Environment.ProcessorCount * 4, Math.Max(4, (int)(currentQueueSize / 1000) + 1) ); } else { // 队列在处理中,保持稳定 desiredThreads = Math.Min( Environment.ProcessorCount * 2, Math.Max(2, (int)(currentQueueSize / 2000) + 1) ); } lock (threadLock) { while (activeThreads < desiredThreads) { StartNewProcessingThread(); } } } public static void ProcessSqlQueue(CancellationToken cancellationToken) { var connectionCache = new Dictionary<string, SqlConnection>(); try { const int maxRetry = 3; const int maxProcessPerCycle = 1000; // 减少每周期处理量以避免长时间占用 const int batchSize = 50; while (!cancellationToken.IsCancellationRequested) { int processedCount = 0; var batchList = new List<DbPoolClass>(batchSize); // 批量获取任务项 while (batchList.Count < batchSize && processedCount < maxProcessPerCycle && World.SqlPool.TryDequeue(out DbPoolClass item)) { batchList.Add(item); processedCount++; } if (batchList.Count == 0) { Thread.Sleep(50); // 队列为空时短暂休眠 continue; } // 按连接字符串分组处理 foreach (var group in batchList.GroupBy(x => x.Conn)) { SqlConnection conn = null; try { // 获取或建连接 if (!connectionCache.TryGetValue(group.Key, out conn) || conn.State != ConnectionState.Open) { SafeCloseConnection(conn, group.Key, connectionCache); conn = new SqlConnection(group.Key); conn.Open(); connectionCache[group.Key] = conn; } // 处理组内所有SQL foreach (var item in group) { if (cancellationToken.IsCancellationRequested) return; int result = DbPoolClass.DbPoolClassRun(conn, item.Sql, item.Prams, item.Type); if (result == -1 && item.RetryCount < maxRetry) { item.RetryCount++; World.SqlPool.Enqueue(item); // 重试 } } } catch (SqlException sqlEx) { Form1.WriteLine(1, $"数据库连接错误[{sqlEx.Number}]: {sqlEx.Message}"); SafeCloseConnection(conn, group.Key, connectionCache); // 重试组内所有项目 foreach (var item in group) { if (item.RetryCount < maxRetry) { item.RetryCount++; World.SqlPool.Enqueue(item); } } } catch (Exception ex) { Form1.WriteLine(1, $"分组执行出错: {ex.Message}"); SafeCloseConnection(conn, group.Key, connectionCache); foreach (var item in group) { if (item.RetryCount < maxRetry) { item.RetryCount++; World.SqlPool.Enqueue(item); } } } } batchList.Clear(); // 动态休眠控制 if (World.SqlPool.Count > 5000) { int sleepTime = Math.Min(100, World.SqlPool.Count / 1000); Thread.Sleep(sleepTime); } } } finally { // 清理所有连接 foreach (var conn in connectionCache.Values) { SafeCloseConnection(conn); } } } private static void SafeCloseConnection(SqlConnection conn, string key = null, Dictionary<string, SqlConnection> cache = null) { try { if (conn != null) { if (conn.State == ConnectionState.Open) conn.Close(); conn.Dispose(); } if (key != null && cache != null && cache.ContainsKey(key)) cache.Remove(key); } catch (Exception ex) { Form1.WriteLine(1, $"关闭连接时出错: {ex.Message}"); } } } } 2025/6/25 2:02:00 数据库队列监控: 当前队列=0, 处理速度=8/秒, 活动线程=4 2025/6/25 2:02:01 网络队列: 连接数=419(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/25 2:02:05 数据库队列监控: 当前队列=193, 处理速度=-38/秒, 活动线程=4 2025/6/25 2:02:06 网络队列: 连接数=419(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/25 2:02:10 数据库队列监控: 当前队列=0, 处理速度=38/秒, 活动线程=4 2025/6/25 2:02:12 网络队列: 连接数=419(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/25 2:02:15 数据库队列监控: 当前队列=678, 处理速度=-135/秒, 活动线程=4 2025/6/25 2:02:17 网络队列: 连接数=419(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/25 2:02:20 数据库队列监控: 当前队列=1151, 处理速度=-94/秒, 活动线程=4 2025/6/25 2:02:22 网络队列: 连接数=419(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/25 2:02:25 数据库队列监控: 当前队列=357, 处理速度=158/秒, 活动线程=4 2025/6/25 2:02:27 网络队列: 连接数=419(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/25 2:02:30 数据库队列监控: 当前队列=937, 处理速度=-116/秒, 活动线程=4 2025/6/25 2:02:32 网络队列: 连接数=419(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/25 2:02:36 数据库队列监控: 当前队列=0, 处理速度=187/秒, 活动线程=4 2025/6/25 2:02:37 网络队列: 连接数=419(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/25 2:02:41 数据库队列监控: 当前队列=328, 处理速度=-65/秒, 活动线程=4 2025/6/25 2:02:42 网络队列: 连接数=419(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/25 2:02:46 数据库队列监控: 当前队列=111, 处理速度=43/秒, 活动线程=4 2025/6/25 2:02:47 网络队列: 连接数=419(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/25 2:02:51 数据库队列监控: 当前队列=58, 处理速度=10/秒, 活动线程=4 2025/6/25 2:02:52 网络队列: 连接数=419(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/25 2:02:56 数据库队列监控: 当前队列=40, 处理速度=3/秒, 活动线程=4 2025/6/25 2:02:57 网络队列: 连接数=419(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/25 2:03:01 数据库队列监控: 当前队列=0, 处理速度=8/秒, 活动线程=4 2025/6/25 2:03:03 网络队列: 连接数=419(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 2025/6/25 2:03:06 数据库队列监控: 当前队列=0, 处理速度=0/秒, 活动线程=4 2025/6/25 2:03:08 网络队列: 连接数=419(活跃=0) 总队列=0KB 最大队列=0字节 过载连接=0 但是新建这个类 我登录了400个假人做测试 列队明显居高不下 而且落差很大 感觉处理很吃力的样子 最明显的是CPU 一会30% 一会96% 大多数都在85%以上使用率 这明显代码有问题啊
06-26
在高并发场景下,数据库队列处理类的性能优化与CPU使用率控制是系统调优的关键环节。以下从多个维度提供优化策略: ### 1. 数据库连接管理优化 - **连接池配置**:合理设置连接池大小,避免连接频繁建和销毁带来的资源浪费。可以使用如`Dapper`或`Entity Framework Core`中的异步操作来提升吞吐量。 - **长连接保持**:确保数据库连接在空闲时不会立即关闭,减少连接建立的开销。 ### 2. SQL 查询优化 - **索引优化**:为队列表中常用的查询字段(如状态、时间戳等)添加合适的索引,避免全表扫描。 - **批量处理**:将多个数据库操作合并为一个批次执行,例如使用`INSERT INTO ... SELECT`或`UPDATE`语句一次性更新多条记录,从而降低网络往返次数和事务开销。 - **避免锁竞争**:在查询中尽量使用`WITH (NOLOCK)`提示(适用于SQL Server)或`READ UNCOMMITTED`隔离级别,以减少锁等待时间[^1]。 ### 3. 异步与并行处理 - **异步编程模型**:采用C#中的`async/await`模式进行异步数据库访问,释放主线程资源,提高响应速度。 - **并行任务调度**:使用`Parallel.ForEach`或`Task.Run`实现多线程并发处理队列项,充分利用多核CPU资源[^1]。 ### 4. 死锁预防与事务管理 - **最小化事务范围**:尽量缩短事务的生命周期,仅在必要时才开启事务,避免长时间持有锁。 - **统一访问顺序**:确保所有事务按照相同的顺序访问资源,减少死锁发生的概率。 - **超时机制**:为每个事务设置合理的超时时间,防止因死锁导致的无限等待。 ### 5. 队列结构设计 - **分片机制**:对队列表进行水平分片,按业务逻辑划分不同的子队列,减少单个队列的竞争压力。 - **优先级队列**:根据任务的重要性或紧急程度分配不同优先级,优先处理高优先级任务。 ### 6. CPU占用率监控与分析 - **线程堆栈分析**:当发现CPU占用率过高时,可以通过分析线程堆栈快速定位问题线程。重点关注用户空间(us)和内核空间(sy)的CPU使用情况[^2]。 - **上下文切换优化**:如果sy值较高且由程序引起,则可能是由于频繁的线程上下文切换所致。此时应考虑减少线程数量或调整线程池配置。 ### 示例代码:异步队列处理 ```csharp public class QueueProcessor { private readonly int _concurrencyLevel; private readonly BlockingCollection<int> _queue; public QueueProcessor(int concurrencyLevel) { _concurrencyLevel = concurrencyLevel; _queue = new BlockingCollection<int>(); } public void StartProcessing() { var tasks = new List<Task>(); for (int i = 0; i < _concurrencyLevel; i++) { tasks.Add(Task.Run(async () => await ProcessQueueAsync())); } // 模拟添加任务到队列 for (int j = 0; j < 1000; j++) { _queue.Add(j); } _queue.CompleteAdding(); Task.WaitAll(tasks.ToArray()); } private async Task ProcessQueueAsync() { foreach (var item in _queue.GetConsumingEnumerable()) { await ProcessItemAsync(item); } } private async Task ProcessItemAsync(int itemId) { using (var connection = new SqlConnection("YourConnectionString")) { await connection.OpenAsync(); var command = new SqlCommand("ProcessQueueItem", connection) { CommandType = CommandType.StoredProcedure }; command.Parameters.AddWithValue("@ItemId", itemId); await command.ExecuteNonQueryAsync(); } } } ``` ### 7. 分布式锁机制 - **Redis分布式锁**:在跨节点或多实例环境下,使用Redis实现分布式锁可以有效协调各节点之间的操作,避免重复处理或数据不一致问题[^3]。 - **乐观锁重试机制**:通过版本号或时间戳实现乐观锁,在发生冲突时自动重试,减少悲观锁带来的阻塞开销。 ### 8. 缓存策略 - **本地缓存**:对于频繁读取但更新较少的数据,可引入本地缓存(如MemoryCache),减少数据库访问频率。 - **二级缓存**:结合Redis等外部缓存服务构建二级缓存体系,进一步减轻数据库负载。 ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

21RGHLY

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值