Skip to content

Commit 8e0fae6

Browse files
authored
Merge pull request #21 from dotnet-campus/t/lindexi/KobarwhawcileNaicewhefai
加上双缓存
2 parents e66884b + 59bc033 commit 8e0fae6

File tree

9 files changed

+506
-1
lines changed

9 files changed

+506
-1
lines changed

AsyncWorkerCollection/AsyncWorkerCollection.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<TargetFrameworks>net45;netcoreapp3.1</TargetFrameworks>
55
<RootNamespace>dotnetCampus.Threading</RootNamespace>
66
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
7+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
78
<AssemblyName>dotnetCampus.AsyncWorkerCollection</AssemblyName>
89
</PropertyGroup>
910

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
2-
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=asynctaskqueue_005F/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
2+
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=asynctaskqueue_005F/@EntryIndexedValue">True</s:Boolean>
3+
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=doublebuffer_005F/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Threading.Tasks;
4+
5+
namespace dotnetCampus.Threading
6+
{
7+
/// <summary>
8+
/// 提供双缓存 线程安全列表
9+
/// </summary>
10+
/// <typeparam name="T">用于存放 <typeparamref name="TU"/> 的集合</typeparam>
11+
/// <typeparam name="TU"></typeparam>
12+
/// 写入的时候写入到一个列表,通过 SwitchBuffer 方法,可以切换当前缓存
13+
public class DoubleBuffer<T, TU> where T : class, ICollection<TU>
14+
{
15+
/// <summary>
16+
/// 创建双缓存
17+
/// </summary>
18+
/// <param name="aList"></param>
19+
/// <param name="bList"></param>
20+
public DoubleBuffer(T aList, T bList)
21+
{
22+
AList = aList;
23+
BList = bList;
24+
25+
CurrentList = AList;
26+
}
27+
28+
/// <summary>
29+
/// 加入元素到缓存
30+
/// </summary>
31+
/// <param name="t"></param>
32+
public void Add(TU t)
33+
{
34+
lock (_lock)
35+
{
36+
CurrentList.Add(t);
37+
}
38+
}
39+
40+
/// <summary>
41+
/// 切换缓存
42+
/// </summary>
43+
/// <returns></returns>
44+
public T SwitchBuffer()
45+
{
46+
lock (_lock)
47+
{
48+
if (ReferenceEquals(CurrentList, AList))
49+
{
50+
CurrentList = BList;
51+
return AList;
52+
}
53+
else
54+
{
55+
CurrentList = AList;
56+
return BList;
57+
}
58+
}
59+
}
60+
61+
/// <summary>
62+
/// 执行完所有任务
63+
/// </summary>
64+
/// <param name="action">当前缓存里面存在的任务,请不要保存传入的 List 参数</param>
65+
public void DoAll(Action<T> action)
66+
{
67+
while (true)
68+
{
69+
var buffer = SwitchBuffer();
70+
if (buffer.Count == 0) break;
71+
72+
action(buffer);
73+
buffer.Clear();
74+
}
75+
}
76+
77+
/// <summary>
78+
/// 执行完所有任务
79+
/// </summary>
80+
/// <param name="action">当前缓存里面存在的任务,请不要保存传入的 List 参数</param>
81+
/// <returns></returns>
82+
public async Task DoAllAsync(Func<T, Task> action)
83+
{
84+
while (true)
85+
{
86+
var buffer = SwitchBuffer();
87+
if (buffer.Count == 0) break;
88+
89+
await action(buffer);
90+
buffer.Clear();
91+
}
92+
}
93+
94+
private readonly object _lock = new object();
95+
96+
private T CurrentList { set; get; }
97+
98+
private T AList { get; }
99+
private T BList { get; }
100+
}
101+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
#nullable enable
2+
using System;
3+
using System.Collections.Generic;
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+
public class DoubleBufferTask<T, TU> : IAsyncDisposable
16+
where T : class, ICollection<TU>
17+
{
18+
/// <summary>
19+
/// 创建双缓存任务,执行任务的方法放在 <paramref name="doTask"/> 方法
20+
/// </summary>
21+
/// <param name="doTask">
22+
/// 执行任务的方法
23+
/// <para></para>
24+
/// 传入的 List&lt;T&gt; 就是需要执行的任务,请不要将传入的 List&lt;T&gt; 保存到本地字段
25+
/// </param>
26+
/// <param name="aList"></param>
27+
/// <param name="bList"></param>
28+
public DoubleBufferTask(T aList, T bList, Func<T, Task> doTask)
29+
{
30+
_doTask = doTask;
31+
DoubleBuffer = new DoubleBuffer<T, TU>(aList, bList);
32+
}
33+
34+
/// <summary>
35+
/// 加入任务
36+
/// </summary>
37+
/// <param name="t"></param>
38+
public void AddTask(TU t)
39+
{
40+
DoubleBuffer.Add(t);
41+
42+
DoInner();
43+
}
44+
45+
private async void DoInner()
46+
{
47+
// ReSharper disable once InconsistentlySynchronizedField
48+
if (_isDoing) return;
49+
50+
lock (DoubleBuffer)
51+
{
52+
if (_isDoing) return;
53+
_isDoing = true;
54+
}
55+
56+
await DoubleBuffer.DoAllAsync(_doTask);
57+
58+
lock (DoubleBuffer)
59+
{
60+
_isDoing = false;
61+
Finished?.Invoke(this, EventArgs.Empty);
62+
}
63+
}
64+
65+
/// <summary>
66+
/// 完成任务
67+
/// </summary>
68+
public void Finish()
69+
{
70+
lock (DoubleBuffer)
71+
{
72+
if (!_isDoing)
73+
{
74+
FinishTask.SetResult(true);
75+
return;
76+
}
77+
78+
Finished += (sender, args) => FinishTask.SetResult(true);
79+
}
80+
}
81+
82+
/// <summary>
83+
/// 等待完成任务,只有在调用 <see cref="Finish"/> 之后,所有任务执行完成才能完成
84+
/// </summary>
85+
/// <returns></returns>
86+
public Task WaitAllTaskFinish()
87+
{
88+
return FinishTask.Task;
89+
}
90+
91+
private TaskCompletionSource<bool> FinishTask { get; } = new TaskCompletionSource<bool>();
92+
93+
private bool _isDoing;
94+
95+
private event EventHandler? Finished;
96+
97+
private readonly Func<T, Task> _doTask;
98+
99+
private DoubleBuffer<T, TU> DoubleBuffer { get; }
100+
101+
/// <inheritdoc />
102+
public async ValueTask DisposeAsync()
103+
{
104+
Finish();
105+
await WaitAllTaskFinish();
106+
}
107+
}
108+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#nullable enable
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Threading.Tasks;
5+
6+
namespace dotnetCampus.Threading
7+
{
8+
/// <summary>
9+
/// 双缓存任务
10+
/// </summary>
11+
/// <typeparam name="T"></typeparam>
12+
public class DoubleBufferTask<T> : DoubleBufferTask<List<T>, T>
13+
{
14+
/// <summary>
15+
/// 创建双缓存任务,执行任务的方法放在 <paramref name="doTask"/> 方法
16+
/// </summary>
17+
/// <param name="doTask"></param>
18+
public DoubleBufferTask(Func<List<T>, Task> doTask) : base(new List<T>(), new List<T>(), doTask)
19+
{
20+
}
21+
}
22+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System.Collections.Generic;
2+
3+
namespace dotnetCampus.Threading
4+
{
5+
/// <summary>
6+
/// 提供双缓存 线程安全列表
7+
/// </summary>
8+
/// 写入的时候写入到一个列表,通过 SwitchBuffer 方法,可以切换当前缓存
9+
public class DoubleBuffer<T> : DoubleBuffer<List<T>, T>
10+
{
11+
/// <summary>
12+
/// 创建使用 <see cref="List&lt;T&gt;"/> 的双缓存
13+
/// </summary>
14+
public DoubleBuffer() : base(new List<T>(), new List<T>())
15+
{
16+
}
17+
}
18+
}

AsyncWorkerCollection/IAsyncDisposable.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,15 @@
44
using System.Text;
55
using System.Threading.Tasks;
66

7+
#if NETFRAMEWORK
8+
using ValueTask = System.Threading.Tasks.Task;
9+
#endif
10+
711
namespace dotnetCampus.Threading
812
{
913
// 这个接口在 .NET Framework 4.5 没有
1014
interface IAsyncDisposable
1115
{
16+
ValueTask DisposeAsync();
1217
}
1318
}

0 commit comments

Comments
 (0)