TH1/Book/2.3单线程异步.md
2025-07-17 18:26:28 +08:00

144 lines
5.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 单线程异步
前面几个例子都是多线程实现的异步但是异步显然不仅仅是多线程的。我们在之前的例子中使用了Sleep来实现时间的等待每一个计时器都需要使用一个线程会导致线程切换频繁这个实现效率很低平常是不会这样做的。一般游戏逻辑中会设计一个单线程的计时器我们这里做一个简单的实现用来讲解单线程异步。
```csharp
// example2_3
class Program
{
private static int loopCount = 0;
private static long time;
private static Action action;
static void Main(string[] args)
{
Console.WriteLine($"主线程: {Thread.CurrentThread.ManagedThreadId}");
Crontine();
while (true)
{
Thread.Sleep(1);
CheckTimerOut();
++loopCount;
if (loopCount % 10000 == 0)
{
Console.WriteLine($"loop count: {loopCount}");
}
}
}
private static void Crontine()
{
WaitTimeAsync(5000, WaitTimeAsyncCallback1);
}
private static void WaitTimeAsyncCallback1()
{
Console.WriteLine($"当前线程: {Thread.CurrentThread.ManagedThreadId}, WaitTimeAsync finsih loopCount的值是: {loopCount}");
WaitTimeAsync(4000, WaitTimeAsyncCallback2);
}
private static void WaitTimeAsyncCallback2()
{
Console.WriteLine($"当前线程: {Thread.CurrentThread.ManagedThreadId}, WaitTimeAsync finsih loopCount的值是: {loopCount}");
WaitTimeAsync(3000, WaitTimeAsyncCallback3);
}
private static void WaitTimeAsyncCallback3()
{
Console.WriteLine($"当前线程: {Thread.CurrentThread.ManagedThreadId}, WaitTimeAsync finsih loopCount的值是: {loopCount}");
}
private static void CheckTimerOut()
{
if (time == 0)
{
return;
}
long nowTicks = DateTime.Now.Ticks / 10000;
if (time > nowTicks)
{
return;
}
time = 0;
action.Invoke();
}
private static void WaitTimeAsync(int waitTime, Action a)
{
time = DateTime.Now.Ticks / 10000 + waitTime;
action = a;
}
}
```
这个例子同样实现了一个简单的计时方法WaitTimeAsync调用时会将回调方法跟时间记录下来主线程每帧都会调用CheckTimerOutCheckTimerOut里面判断计时器是否过期过期了则调用回调方法。整个逻辑都在主线程中完成同样是异步方法。所以异步并非多线程单线程同样可以异步。上面的例子同样可以改成await的形式。
```csharp
// example2_3_2
class Program
{
private static int loopCount = 0;
private static long time;
private static TaskCompletionSource<bool> tcs;
static void Main(string[] args)
{
Console.WriteLine($"主线程: {Thread.CurrentThread.ManagedThreadId}");
Crontine();
while (true)
{
Thread.Sleep(1);
CheckTimerOut();
++loopCount;
if (loopCount % 10000 == 0)
{
Console.WriteLine($"loop count: {loopCount}");
}
}
}
private static async void Crontine()
{
await WaitTimeAsync(5000);
Console.WriteLine($"当前线程: {Thread.CurrentThread.ManagedThreadId}, WaitTimeAsync finsih loopCount的值是: {loopCount}");
await WaitTimeAsync(4000);
Console.WriteLine($"当前线程: {Thread.CurrentThread.ManagedThreadId}, WaitTimeAsync finsih loopCount的值是: {loopCount}");
await WaitTimeAsync(3000);
Console.WriteLine($"当前线程: {Thread.CurrentThread.ManagedThreadId}, WaitTimeAsync finsih loopCount的值是: {loopCount}");
}
private static void CheckTimerOut()
{
if (time == 0)
{
return;
}
long nowTicks = DateTime.Now.Ticks / 10000;
if (time > nowTicks)
{
return;
}
time = 0;
tcs.SetResult(true);
}
private static Task WaitTimeAsync(int waitTime)
{
TaskCompletionSource<bool> t = new TaskCompletionSource<bool>();
time = DateTime.Now.Ticks / 10000 + waitTime;
tcs = t;
return t.Task;
}
}
```
上面这个例子所有调用全部在主线程中完成并且使用了await因此await并不会开启多线程await具体用没用多线程完全取决于具体的实现