C# 异步编程

异步编程

使用了关键字await,必须使用async,返回的类型必须是Task

所有异步编程都要使用await

程序不包含适合于入口点的静态 “Main” 方法 ConsoleApp1 D:\Desk\力扣\ConsoleApp1\CSC 1 活动 程序不包含适合于入口点的静态 “Main” 方法

namespace ConsoleApp1
{
    internal class Program
    {
        //static async void Main(string[] args)  //错误
        static async Task Main(string[] args)
        {
            //Console.WriteLine("Hello, World!");
            //string filename = @"D:\Desk\dumps\aa.txt";
            //File.WriteAllText(filename, "hello");
            //Console.WriteLine(File.ReadAllText(filename));

            string filename = @"D:\Desk\dumps\aa.txt";
            await File.WriteAllTextAsync(filename, "keson,你好呀");
        }
    }
}

自己定义异步方法

namespace ConsoleApp1
{
    internal class Program
    {
        static async Task Main(string[] args)
        {
            await DownloadHtmlAsync("https://www.baidu.com", @"D:\Desk\dumps\aa.txt");
            

        }

        //编写异步方法
        static async Task DownloadHtmlAsync(string url,string filename)
        {
            using(HttpClient httpclient = new HttpClient())
            {
                string html =await httpclient.GetStringAsync(url);
                await File.WriteAllTextAsync(filename, html);
            }
            
        }

        static async Task<int> Lenth_DownloadHtmlAsync(string url, string filename)
        {
            using (HttpClient httpclient = new HttpClient())
            {
                string html = await httpclient.GetStringAsync(url);
                await File.WriteAllTextAsync(filename, html);
                return html.Length;
            }

        }
    }
}

调用封装好的方法会在新线程中执行

internal class Program
{
    static async Task Main(string[] args)
    {
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < 10000; i++)
        {
            sb.AppendLine("hello");
        }
        await File.WriteAllTextAsync(@"D:\Desk\dumps\aa.txt",sb.ToString());
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
    }

    //编写异步方法
    static async Task DownloadHtmlAsync(string url,string filename)
    {
        using(HttpClient httpclient = new HttpClient())
        {
            string html =await httpclient.GetStringAsync(url);
            await File.WriteAllTextAsync(filename, html);
        }

    }
}

调用异步方法并不会开启新线程,除非在Task.Run里面运行. 而上面的例子是运行封装好的例子,所以会在新线程中运行

using System.Text;

namespace ConsoleApp1
{
    internal class Program
    {
        static async Task Main(string[] args)
        {
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
            await TestFunction();
            await Task.Run(() =>
            {
                Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
                for (int i = 0; i < 100000; i++) { }

            });
        }

        static async Task TestFunction()
        {
            for(int i = 0;i <10000;i++)
            {

            }
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
        }
    }
}

异步方法可以不写async关键字

        static  Task<string> TestFunction()
        {
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId);

            return File.ReadAllTextAsync(@"D:\Desk\dumps\aa.txt");
        }

异步编程不要用Thread.Sleep,它有可能会阻止当前线程.需要改用Delay

C#编程,异步中的等待处理Task.Delay-CSDN博客

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private  void button1_Click(object sender, EventArgs e)
        {

            Task task = Task.Factory.StartNew(() =>
            {
                Console.WriteLine($" Task.Delay开始:{DateTime.Now.ToString(" HH:mm:ss.fff")}");
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine($" {DateTime.Now.ToString("HH:mm:ss.fff")} 正在进行:{i}");
                    Task.Delay(2000);
                }
                Console.WriteLine($" Task.Delay结束:{DateTime.Now.ToString("HH:mm:ss.fff")}");
                //Console.ReadKey();
            });

        }

        private void button2_Click(object sender, EventArgs e)
        {
            Task task = Task.Factory.StartNew(async () =>
            {
                Console.WriteLine($" Task.Delay 有await 开始:{DateTime.Now.ToString("HH:mm:ss.fff")}");
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine($" {DateTime.Now.ToString("HH:mm:ss.fff")} 有await正在进行:{i}");
                    await Task.Delay(2000);
                }
                Console.WriteLine($" Task.Delay 有await 结束:{DateTime.Now.ToString("HH:mm:ss.fff")}");
                Console.ReadKey();
            });

        }

        private void button3_Click(object sender, EventArgs e)
        {
            Task task = Task.Factory.StartNew(() =>
            {
                Console.WriteLine($" Task.Delay 有await 开始:{DateTime.Now.ToString("HH:mm:ss.fff")}");
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine($" {DateTime.Now.ToString("HH:mm:ss.fff")} 有await正在进行:{i}");
                    Thread.Sleep(2000);
                }
                Console.WriteLine($" Task.Delay 有await 结束:{DateTime.Now.ToString("HH:mm:ss.fff")}");
                Console.ReadKey();
            });
        }
    }
}

请求取消时的处理

internal class Program
    {
        static async Task Main(string[] args)
        {
            CancellationTokenSource cts = new CancellationTokenSource();
            cts.CancelAfter(5000);
            await DownloadHtmlAsync("https://www.baidu.com", @"D:\Desk\dumps\aa.txt",cts.Token);
        }

        //编写异步方法
        static async Task DownloadHtmlAsync(string url,string filename,CancellationToken cancellationToken)
        {
            using(HttpClient httpclient = new HttpClient())
            {
                for (int i = 0;i < 50; i++)
                {
                    string html = await httpclient.GetStringAsync(url);
                    Console.WriteLine($"{DateTime.Now}:{html}");
                    if (cancellationToken.IsCancellationRequested)
                    {
                        Console.WriteLine("请求取消");
                        break;
                    }                    
                }

            }            
        }
}

AutoResetEvent用法

  • 通过Event.waitone()阻塞当前线程

  • 通过Event.set()发出信号,通知阻塞线程是否继续; 如果阻塞线程有多个,收到set信号时哪个线程先执行,是随机的.

class Example
{
    private static AutoResetEvent event_1 = new AutoResetEvent(true);
    private static AutoResetEvent event_2 = new AutoResetEvent(false);

    static void Main()
    {
        Console.WriteLine("Press Enter to create three threads and start them.\r\n" +
                          "The threads wait on AutoResetEvent #1, which was created\r\n" +
                          "in the signaled state, so the first thread is released.\r\n" +
                          "This puts AutoResetEvent #1 into the unsignaled state.");
        Console.ReadLine();

        for (int i = 1; i < 4; i++)
        {
            Thread t = new Thread(ThreadProc);
            t.Name = "Thread_" + i;
            t.Start();
        }
        Thread.Sleep(250);

        for (int i = 0; i < 2; i++)
        {
            Console.WriteLine("Press Enter to release another thread.");
            Console.ReadLine();
            event_1.Set();
            Thread.Sleep(250);
        }

        Console.WriteLine("\r\nAll threads are now waiting on AutoResetEvent #2.");
        for (int i = 0; i < 3; i++)
        {
            Console.WriteLine("Press Enter to release a thread.");
            Console.ReadLine();
            event_2.Set();
            Thread.Sleep(250);
        }

        // Visual Studio: Uncomment the following line.
        //Console.Readline();
    }

    static void ThreadProc()
    {
        string name = Thread.CurrentThread.Name;

        Console.WriteLine("{0} waits on AutoResetEvent #1.", name);
        event_1.WaitOne();
        Console.WriteLine("{0} is released from AutoResetEvent #1.", name);

        Console.WriteLine("{0} waits on AutoResetEvent #2.", name);
        event_2.WaitOne();
        Console.WriteLine("{0} is released from AutoResetEvent #2.", name);

        Console.WriteLine("{0} ends.", name);
    }
}

Mutex的用法

核心: 使用Mutex.waitone 和 Mutex.ReleaseMutex(), 对两者者之间的代码保持独占(独有);

下面的代码就是,当一个线性先进入保护区域, 该线程就会独有这段代码, 其他线程要调用该方法时, 就会在waitone()那里等待, 直到Mutex被释放, 其他线程才能进入保护区域, 如果有很多线程等待进入该区域, 进入该保护区域是随机的

using System;
using System.Threading;

class Example
{
    // Create a new Mutex. The creating thread does not own the mutex.
    private static Mutex mut = new Mutex();
    private const  int numIterations = 1;
    private const int numThreads = 3;

    static void Main()
    {
        // Create the threads that will use the protected resource.
        for (int i = 0; i < numThreads; i++)
        {
            Thread newThread = new Thread(new ThreadStart(ThreadProc));
            newThread.Name = String.Format("Thread{0}", i + 1);
            newThread.Start();
        }

        // The main thread exits, but the application continues to
        // run until all foreground threads have exited.
    }

    private static void ThreadProc()
    {
        for (int i = 0; i < numIterations; i++)
        {
            UseResource();
        }
    }

    // This method represents a resource that must be synchronized
    // so that only one thread at a time can enter.
    private static void UseResource()
    {
        // Wait until it is safe to enter.
        Console.WriteLine("{0} is requesting the mutex",
                          Thread.CurrentThread.Name);
        mut.WaitOne();

        Console.WriteLine("{0} has entered the protected area",
                          Thread.CurrentThread.Name);

        // Place code to access non-reentrant resources here.

        // Simulate some work.
        Thread.Sleep(500);

        Console.WriteLine("{0} is leaving the protected area",
            Thread.CurrentThread.Name);

        // Release the Mutex.
        mut.ReleaseMutex();
        Console.WriteLine("{0} has released the mutex",
            Thread.CurrentThread.Name);
    }
}

结果:

Thread1 is requesting the mutex
Thread2 is requesting the mutex
Thread3 is requesting the mutex
Thread1 has entered the protected area
Thread1 is leaving the protected area
Thread1 has released the mutex
Thread3 has entered the protected area
Thread3 is leaving the protected area
Thread3 has released the mutex
Thread2 has entered the protected area
Thread2 is leaving the protected area
Thread2 has released the mutex
  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值