首页 > 代码库 > C#并发编程

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的实现

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的内存

 

C#并发编程