144 lines
5.0 KiB
Markdown
144 lines
5.0 KiB
Markdown
# 单线程异步
|
||
前面几个例子都是多线程实现的异步,但是异步显然不仅仅是多线程的。我们在之前的例子中使用了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调用时会将回调方法跟时间记录下来,主线程每帧都会调用CheckTimerOut,CheckTimerOut里面判断计时器是否过期,过期了则调用回调方法。整个逻辑都在主线程中完成,同样是异步方法。所以异步并非多线程,单线程同样可以异步。上面的例子同样可以改成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具体用没用多线程完全取决于具体的实现
|