Skip to content

Commit ec2c616

Browse files
authored
Merge pull request #34 from dotnet-campus/t/lindexi/LimitedRunningCountTask
限制执行数量的任务
2 parents 4d70191 + 165c7f8 commit ec2c616

File tree

1 file changed

+233
-0
lines changed

1 file changed

+233
-0
lines changed
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
#nullable enable
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
6+
#if NETFRAMEWORK
7+
using ValueTask = System.Threading.Tasks.Task;
8+
#endif
9+
10+
namespace dotnetCampus.Threading
11+
{
12+
/// <summary>
13+
/// 限制执行数量的任务,执行的任务超过设置的数量将可以等待直到正在执行任务数小于设置的数量
14+
/// </summary>
15+
#if PublicAsInternal
16+
internal
17+
#else
18+
public
19+
#endif
20+
class LimitedRunningCountTask
21+
{
22+
/// <summary>
23+
/// 创建限制执行数量的任务
24+
/// </summary>
25+
/// <param name="maxRunningCount">允许最大的执行数量的任务</param>
26+
public LimitedRunningCountTask(uint maxRunningCount)
27+
{
28+
MaxRunningCount = maxRunningCount;
29+
}
30+
31+
/// <summary>
32+
/// 执行的任务数
33+
/// </summary>
34+
public int RunningCount
35+
{
36+
set
37+
{
38+
lock (Locker)
39+
{
40+
_runningCount = value;
41+
}
42+
}
43+
get
44+
{
45+
lock (Locker)
46+
{
47+
return _runningCount;
48+
}
49+
}
50+
}
51+
52+
/// <summary>
53+
/// 允许最大的执行数量的任务
54+
/// </summary>
55+
public uint MaxRunningCount { get; }
56+
57+
/// <summary>
58+
/// 加入执行任务
59+
/// </summary>
60+
/// <param name="task"></param>
61+
public void Add(Task task)
62+
{
63+
RunningCount++;
64+
lock (Locker)
65+
{
66+
Buffer.Add(task);
67+
68+
RunningBreakTask?.TrySetResult(true);
69+
}
70+
71+
RunningInner();
72+
}
73+
74+
/// <summary>
75+
/// 加入等待任务,在空闲之后等待才会返回
76+
/// </summary>
77+
/// <param name="task"></param>
78+
/// <returns></returns>
79+
public async ValueTask AddAsync(Task task)
80+
{
81+
// ReSharper disable once MethodHasAsyncOverload
82+
Add(task);
83+
await WaitForFree();
84+
}
85+
86+
/// <summary>
87+
/// 等待空闲
88+
/// </summary>
89+
/// <returns></returns>
90+
public async ValueTask WaitForFree()
91+
{
92+
if (WaitForFreeTask == null)
93+
{
94+
return;
95+
}
96+
97+
await WaitForFreeTask.Task;
98+
}
99+
100+
private TaskCompletionSource<bool>? RunningBreakTask
101+
{
102+
set
103+
{
104+
lock (Locker)
105+
{
106+
_runningBreakTask = value;
107+
}
108+
}
109+
get
110+
{
111+
lock (Locker)
112+
{
113+
return _runningBreakTask;
114+
}
115+
}
116+
}
117+
118+
private TaskCompletionSource<bool>? WaitForFreeTask
119+
{
120+
set
121+
{
122+
lock (Locker)
123+
{
124+
_waitForFreeTask = value;
125+
}
126+
}
127+
get
128+
{
129+
lock (Locker)
130+
{
131+
return _waitForFreeTask;
132+
}
133+
}
134+
}
135+
136+
private List<Task> Buffer { get; } = new List<Task>();
137+
138+
private object Locker => Buffer;
139+
140+
private bool _isRunning;
141+
142+
private int _runningCount;
143+
144+
private TaskCompletionSource<bool>? _runningBreakTask;
145+
146+
private TaskCompletionSource<bool>? _waitForFreeTask;
147+
148+
private async void RunningInner()
149+
{
150+
// ReSharper disable once InconsistentlySynchronizedField
151+
if (_isRunning)
152+
{
153+
return;
154+
}
155+
156+
lock (Locker)
157+
{
158+
if (_isRunning)
159+
{
160+
return;
161+
}
162+
163+
_isRunning = true;
164+
}
165+
166+
List<Task> runningTaskList;
167+
lock (Locker)
168+
{
169+
runningTaskList = Buffer.ToList();
170+
Buffer.Clear();
171+
RunningBreakTask = new TaskCompletionSource<bool>();
172+
runningTaskList.Add(RunningBreakTask.Task);
173+
174+
SetWaitForFreeTask();
175+
}
176+
177+
while (runningTaskList.Count > 0)
178+
{
179+
// 加入等待
180+
await Task.WhenAny(runningTaskList);
181+
182+
// 干掉不需要的任务
183+
runningTaskList.RemoveAll(task => task.IsCompleted);
184+
185+
lock (Locker)
186+
{
187+
runningTaskList.AddRange(Buffer);
188+
Buffer.Clear();
189+
190+
RunningCount = runningTaskList.Count;
191+
192+
if (!RunningBreakTask.Task.IsCompleted)
193+
{
194+
runningTaskList.Add(RunningBreakTask.Task);
195+
}
196+
else
197+
{
198+
RunningBreakTask = new TaskCompletionSource<bool>();
199+
runningTaskList.Add(RunningBreakTask.Task);
200+
}
201+
202+
if (runningTaskList.Count < MaxRunningCount)
203+
{
204+
WaitForFreeTask?.TrySetResult(true);
205+
}
206+
else
207+
{
208+
SetWaitForFreeTask();
209+
}
210+
}
211+
}
212+
213+
lock (Locker)
214+
{
215+
_isRunning = false;
216+
}
217+
218+
void SetWaitForFreeTask()
219+
{
220+
if (runningTaskList.Count > MaxRunningCount)
221+
{
222+
if (WaitForFreeTask?.Task.IsCompleted is false)
223+
{
224+
}
225+
else
226+
{
227+
WaitForFreeTask = new TaskCompletionSource<bool>();
228+
}
229+
}
230+
}
231+
}
232+
}
233+
}

0 commit comments

Comments
 (0)