-
创建一个函数来模拟时间消耗的方法,此处为
GetSomeThing
函数。 -
要使用异步编程,需要使用一个async修饰的方法来包装调用
GetSomeThing
函数,此函数的返回值为Task类型,该类型表示进行并行运算的任务引用。此处示例为ConsumeManyTime
函数。 - 现在就可以直接使用异步方式了,参考
TestOne()
函数中的代码,其实就是直接调用第二步中的函数ConsumeManyTime()
;
总结:
异步编程虽然示例三步,但是实际上就是两步的事情,第一步是模拟应用,跟异步编程本身没有关系,第二步包装一个Task返回类型的async
修饰的方法,该方法实际调用应用函数,第三步调用第二步的方法,从而执行对模拟应用的异步执行。
附加:
除了异步编程以外,C#还提供了并发编程相关功能,极大简化了并发任务的开发,可以让开发人员无需创建线程池以及管理线程这些工作,就可以直接使用并发开发带来的优势。 示例代码见Testpallral()
。
代码如下
class Program
{
static int i = 0;
//模拟耗时的运算或者IO
public static bool GetSomeThing(string a)
{
Thread.Sleep((new Random()).Next()%10*1000);
i++;
Console.WriteLine(DateTime.Now.ToLongTimeString()+"5-" + Thread.GetCurrentProcessorId().ToString());
return true;
}
//生成一个task类型,其中包装调用GetSomeThing
public static Task<bool> GetSomeThingAsync(string a)
{
return Task.Run<bool>(()=> { return GetSomeThing(a); }
);
}
//方式1:包装给调用方使用的方法,使用async修饰,因为里面有await。 调用方执行到await会立即返回,后续的内容不再直接调用, await之后的方法都会在可能在其他线程中使用,
public async static void ConsumeManyTime()
{
Console.WriteLine(DateTime.Now.ToLongTimeString() + "3-" +Thread.GetCurrentProcessorId().ToString());
bool result = await GetSomeThingAsync("test");
Console.WriteLine(DateTime.Now.ToLongTimeString() + "4-" +Thread.GetCurrentProcessorId().ToString());
}
//方式2:这种调用方式是在异步执行完毕后,可以继续执行预定的后续函数,可以理解为一种回调机制。
public static void ContinueTaskWithConsumeManyTime()
{
Task<bool> t1 = GetSomeThingAsync("test");
t1.ContinueWith(t => { Console.WriteLine("after await finished " + t.Result + " " + Thread.GetCurrentProcessorId().ToString() + " " + i.ToString()); });
}
//方式3:多任务等待方式
public static async void TaskWhenConsumeManyTime()
{
Task<bool> t1 = GetSomeThingAsync("test");
Task<bool> t2 = GetSomeThingAsync("test");
await Task.WhenAll(t1, t2);
Console.WriteLine(DateTime.Now.ToLongTimeString() + "6-" + Thread.GetCurrentProcessorId().ToString());
}
//async 和await的基本使用
public static void TestOne()
{
Console.WriteLine(DateTime.Now.ToLongTimeString() + "1-" + Thread.GetCurrentProcessorId().ToString());
ConsumeManyTime();
ConsumeManyTime();
Console.WriteLine(DateTime.Now.ToLongTimeString() + "2-" + Thread.GetCurrentProcessorId().ToString());
Console.WriteLine("继续输入");
while (Console.ReadLine() != "stop")
{
Console.WriteLine("继续输入");
}
}
public static void TestWithContinue()
{
Console.WriteLine(DateTime.Now.ToLongTimeString() + "1-" + Thread.GetCurrentProcessorId().ToString());
ContinueTaskWithConsumeManyTime();
ContinueTaskWithConsumeManyTime();
Console.WriteLine(DateTime.Now.ToLongTimeString() + "2-" + Thread.GetCurrentProcessorId().ToString());
Console.WriteLine("继续输入");
while (Console.ReadLine() != "stop")
{
Console.WriteLine("继续输入");
}
}
public static void TestWhen()
{
Console.WriteLine(DateTime.Now.ToLongTimeString() + "1-" + Thread.GetCurrentProcessorId().ToString());
TaskWhenConsumeManyTime();
Console.WriteLine(DateTime.Now.ToLongTimeString() + "2-" + Thread.GetCurrentProcessorId().ToString());
Console.WriteLine("继续输入");
while (Console.ReadLine() != "stop")
{
Console.WriteLine("继续输入");
}
}
public static void Testpallral()
{
ParallelLoopResult result =
Parallel.For(0, 100, async (int i) =>
{
Console.WriteLine(DateTime.Now.ToLongTimeString() + "{0}, task: {1}, thread: {2}", i,
Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
await Task.Delay(10);
Console.WriteLine(DateTime.Now.ToLongTimeString() + "after delay");
});
while (Console.ReadLine() != "stop")
{
Console.WriteLine("继续输入");
}
}
public static void Testpallral2()
{
ParallelLoopResult result =
Parallel.For(0, 100,async(int i, ParallelLoopState pls) =>
{
Console.WriteLine(DateTime.Now.ToLongTimeString() + "{0}, task: {1}, thread: {2}", i,
Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
await Task.Delay(10);
if (i > 5) pls.Break();
Console.WriteLine(DateTime.Now.ToLongTimeString() + "after delay");
}
);
while (Console.ReadLine() != "stop")
{
Console.WriteLine("继续输入");
}
}
static void Main(string[] args)
{
//TestWhen();
//Testpallral2();
}
}