zoukankan      html  css  js  c++  java
  • C#并发编程

    最近看C# 并发编程··,这里做一下总结··多线程,异步,并行,大部分都是最近看C#并发编程这个书涉及到的··这里仅仅列出实现方式,书里边介绍的其他的东西没有涉及比如取消操作,同步操作,集合之类的东西

    线程:Thread,ThreadPool,BackgroundWorker,

    Thread 可以又更多控制··ThreadPool就是丢进去系统好管理线程,BackgroundWorker相当于加了事件的线程,用在thread执行函数里边加事件,外边注册加invoke就可以实现类似backgroundworker的功能,

    但是机制好像不太一样,看了反编译的方法invoke里边的代码 带了大量的非托管代码··看不大懂··,backgroundworker内部使用委托的异步执行方式,就是begininvoke,  C#的begininvoke内部实现好像就是多线程,通过同步上下文回到ui线程实现类似invoke 的操作

    thread 和threadpool都可以传递一个委托进去,这样可以通过委托做一些特殊操作··也可以直接定义个事件实现通知进度的功能

    4.5的async/await  里边iprogress也能实现类似报告进度功能

     代码在winform窗体里边执行               
     private event EventHandler myevent;
    //thread myevent += delegate { Invoke(new EventHandler(delegate { Text = "threadtest"; })); }; Action myaction = new Action(() => { MessageBox.Show("delegatetest"); }); new Thread(new ParameterizedThreadStart((obj) => { //dosomthing Thread.Sleep(2000); (obj as Action)(); })).Start(myaction); new Thread(new ThreadStart(() => { //dosomething Thread.Sleep(2000); myevent?.Invoke(null, new EventArgs()); })).Start(); //backgroundworker BackgroundWorker worker = new BackgroundWorker(); worker.WorkerReportsProgress = true; worker.DoWork += delegate { //dosomething Thread.Sleep(2000); worker.ReportProgress(100); }; worker.ProgressChanged += (send, stat) => { Text = "doworker"; }; worker.RunWorkerAsync(); //threadpool ThreadPool.QueueUserWorkItem(new WaitCallback((stat) => { //dosomthing Thread.Sleep(1000); })); //task 异步 Task t = new Task(() => { //dosomething Thread.Sleep(3000); }); Action<Task> taction = new Action<Task>((tas) => { Text = "Task"; }); var context = TaskScheduler.FromCurrentSynchronizationContext();//这里创建一个当前上下文的任务调度器,其实就是当前的ui线程上下文 t.ContinueWith(taction, context);//吧上边的调度器传入,接着的这个任务就会用这个调度器执行,内部其实就是post方法把操作放在当前ui线程进行同步执行,这样就不会报错了 t.Start();//这里是异步的方式,默认是以线程池的方式执行,如果在这里放入ui操作会报错线程间操作无效

    之前的异步编程,通过beginInvoke ,委托和control都有类似方法,invoke就是同步执行, begininvoke异步执行,这个里边据说也是用线程池实现的异步

                Action act = new Action(() => {
                    Thread.Sleep(2000);
                    Console.WriteLine("121231");
                });
                var callback = new AsyncCallback((iasynccallback) =>
                {
                    Console.WriteLine("OK");
                });
                var res=act.BeginInvoke(callback, null);
                Console.WriteLine("异步测试");
                act.EndInvoke(res);

    上边有Task的写法,task通过任务调度器也就是TaskScheduler来实现调度,可以在当前线程执行,也可以通过线程池执行,这个TaskScheduler 有两种实现,一种是用线程池实现,一种用上下文实现类似上边的backgroundworker,

    也就是SynchronizationContext这个类,这个类又一个Post方法可以将异步的方法以同步的方式执行到指定的上下文中去,

    而4.5里边的async/await也是以类似的方式,又上下文这个概念,这个async/await 花样可多了···这里就不多说了。。。

    这里举个例子,可以把窗体时间直接定义为异步函数,这样事件方法里边用await去异步执行,而在方法中又可以直接刷新ui,下边的代码是可以运行成功的· 这个完全颠覆了之前的写法··之前的如果要进行异步,比如线程中要更新ui就要invoke否则肯定要报错,或者使用上面委托的异步执行通过回调函数的方式去执行ui刷新应该也是要invoke的

     btn.Click += Displaywebstringlength;
    
    
            async void Displaywebstringlength(object sender,EventArgs e)
            {
                label.Text = "Fethcing";
                using (HttpClient client = new HttpClient())                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
                {
                    string text =await client.GetStringAsync(@"https://www.baidu.com/");
                    label.Text = text.Length.ToString();
                }
            }

    并行·

    当有大量的不相干的事的集合要进行操作就可以用并行了也就是Parallel,这玩意内部也是用task实现的但是实现写好复杂 没看明白·····总之碉堡了···

    也可以用对应的linq实现PLINQ,

    建议使用Parallel 这个会根据cpu状态动态调整,而plinq没有这个考虑

    比如我有一堆文件要读取,就可以这样读,或者我要检查局域网的那些IP能ping同,或者做一些数字的聚合操作

                var nums = Enumerable.Range(1, 20);
                Parallel.ForEach(nums, new Action<int>(n => Console.WriteLine(n)));//Parallel的实现
                nums.AsParallel().ForAll(n => Console.WriteLine(n));//Plinq的实现
    //任务并行执行       

    Action maction = () => {
    Console.WriteLine("ParelTest");
    };
    Parallel.Invoke(maction);

    TPL数据流,就是把事件弄的想流一样执行·· 我实在没搞明白这玩意又啥用 反正很流弊l啦,这个东西需要用nuget下一个微软的库,这个库是额外,也就是不包含在fcl中,Microsoft.Tpl.Dataflow

            static async Task Test()
            {
                //string uri = @"https://www.baidu.com/";
                //string res = await DownloadWrithRitries(uri);
                //Console.WriteLine(res); 
                var multiplyBlock = new TransformBlock<int, int>(item => {
                    item = item * 2;
                    Console.WriteLine(item);
                    return item;
                });
                var substractblock = new TransformBlock<int, int>(item => {
                    item = item - 2;
                    Console.WriteLine(item);
                    return item;
                });
                var opions = new DataflowLinkOptions { PropagateCompletion = true };
                multiplyBlock.LinkTo(substractblock, opions);
                multiplyBlock.AsObserver().OnNext(20);
                multiplyBlock.Complete();
                await substractblock.Completion;
            }

    Rx这个也是要通过nuget安装Rx-Main,这玩意是基于IObservable<T>也就是观察者模式·的玩意··这里不做解释了···主要是我的nuget没下到这玩意·····

    这里这是列举了这些异步的方式· 应该都支持取消操作,类似CancellationTokenSource这个类型的东西·

    所以书里边推荐使用Task和async/await,

    然后还有涉及同步方式的问题主要是阻塞锁,异步锁SemaphoreSlim(其实是限流),阻塞信号

    或者使用线程安全集合比如ConcurrentBag,ConcurrentDictionary分别对应列表和字典的线程安全集合,类似的还有栈和队列以及set的实现,这玩意内部实现好像就是monitor和innerlock配合,说是效率还可以·

    ·贴个代码··这个是反编译的ConcurrentBag的添加操作代码

    private void AddInternal(ConcurrentBag<T>.ThreadLocalList list, T item)
    {
        bool flag = false;
        try
        {
            Interlocked.Exchange(ref list.m_currentOp, 1);
            if (list.Count < 2 || this.m_needSync)
            {
                list.m_currentOp = 0;
                Monitor.Enter(list, ref flag);
            }
            list.Add(item, flag);
        }
        finally
        {
            list.m_currentOp = 0;
            if (flag)
            {
                Monitor.Exit(list);
            }
        }
    }

    另外微软还有一个不可变集合库,这玩意需要去nuget下载,都是以Immutable开头的··

    所谓的不可变意思是每次操作都返回一个全新的集合,在api实现的时候集合里边实现的存储共享···具体怎么实现就不知道了

              var stack = ImmutableStack<int>.Empty;
                    stack = stack.Push(13);
                    var biggerstack = stack.Push(7);
                    foreach (var item in stack)
                        Console.WriteLine(item);
                    foreach (var item in biggerstack)
                        Console.WriteLine(item);
    //两个栈共享了存储项目13的内存
  • 相关阅读:
    主题样式切换代码:jQuery Theme Switcher
    MongoDB北大绿卡之安全建议
    Sketch 快速创建调色板技巧(PS 同样适用)
    你未必知道的12个JavaScript技巧
    js 面向对象 打气球小游戏
    js 行走的小女孩 面向对象
    js 小练习题
    css 实现九宫格
    JDK java version "1.8.0_181"环境搭建
    juery 弹出框
  • 原文地址:https://www.cnblogs.com/onegarden/p/7113102.html
Copyright © 2011-2022 走看看