彩世界开奖app官网-彩世界平台官方网址(彩票平台)
做最好的网站
来自 计算机编程 2019-10-16 03:06 的文章
当前位置: 彩世界开奖app官网 > 计算机编程 > 正文

C#线程安全使用(五)

2,Task运行线程,传递CancellationToken。Task传递方式分为二种,一种通过Task的参数实行传递,另一种通过向线程内传递对象的方式传递CancellationToken。

(5)集合

  1. 线程安全集结是可同不常间被四个线程修改的可变集结。线程安全集结混合使用了细粒度锁定和无锁技巧,以保险线程被打断的岁月最短(日常景况下是根本不打断)。对很四线程安全集合举办枚举操作时,内部创建了该集结的贰个快速照相(snapshot),并对那么些快速照相举办枚举操作。线程安全集结的首要性优点是三个线程能够安全地对其打开探望,而代码只会被卡住相当短的时光,或根本不打断

  2. ConcurrentDictionary是数据结构中的极品,它是线程安全的,混合使用了细粒度锁定和无锁本领,以有限援助半数以上动静下能进行高效访问.

  3. ConcurrentDictionary 内置了AddOrUpdate, TryRemove, TryGetValue等艺术。如若八个线程读写一个分享会集,使用ConcurrentDictionary是最合适的,借使不会每每修改,那就更切合利用ImmutableDictionary。而一旦是有些线程只添日元素,一些线程只移除成分,最棒使用生产者/花费者集结

 CancellationToken的有余接纳

1.前言

近期趁着系列的一段平稳期研读了过多书本,当中《C#并发编制程序经典实例》给自个儿的回忆可能相比深远的。当然,那只怕是出于近段日子看的书好些个嘴炮大于实际,如《Head First设计方式》《Cracking the coding interview》等,所以蓦然见到一本打着“实例”暗记的书籍,依旧挺让本身认为万象更新。本着分享和深化通晓的指标,笔者特地整理了一些笔记(首假如Web开辟中易于涉及的剧情,所以有个别章节如数据流,福睿斯X等自家看了看就一向跳过了),以供审阅学习。语言和技巧的魅力,真是不得捉摸

 后记

3.付出原则和中央

但是,也说不定是目前写文字的技术有所进步,所以就完了了四和五。

(7)同步

  1. 一块的体系首要有三种:通讯和数据爱护

  2. 假诺上边多个尺码都满意,就必要用协同来珍视分享的多寡

  • 多段代码正在出现运转
  • 这几段代码在做客(读或写)同三个数码
  • 最少有一段代码在修改(写)数据
  1. 考查以下代码,分明其一同和周转境况
class SharedData
{
    public int Value { get; set; }
}

async Task ModifyValueAsync(SharedData data)
{
    await Task.Delay(TimeSpan.FromSeconds(1));
    data.Value = data.Value   1;
}

// 警告:可能需要同步,见下面的讨论。
async Task<int> ModifyValueConcurrentlyAsync()
{
    var data = new SharedData();

    // 启动三个并发的修改过程。
    var task1 = ModifyValueAsync(data);
    var task2 = ModifyValueAsync(data);
    var task3 = ModifyValueAsync(data);

    await Task.WhenAll(task1, task2, task3);

    return data.Value;
}

本例中,运转了四个并发运维的改换进度。须求联合啊?答案是“看事态”。假设能显明那个方式是在 GUI 或 ASP.NET 上下文中调用的(或同时内只允许一段代码运营的任 何其余上下文),那就不必要一齐,因为这八个修改数据经过的运作时刻是互不一致的。 比如,假使它在 GUI 上下文中运营,就唯有五个 UI 线程可以运维这个多少修改进程,因此一段时间内只好运行五个经过。由此,如若可以规定是“同时只运行一段代码”的 上下文,那就无需共同。不过假若从线程池线程(如 Task.Run)调用那几个法子,就须要一齐了。在这里种景况下,那七个数据修改进度会在独立的线程池线程中运作,何况还要修改 data.Value,由此必需共同地拜候 data.Value。

  1. 不可变类型本身正是线程安全的,修改贰个不可变集结是不可能的,即使使用三个Task.Run向聚聚集添扩张少,也并无需同步操作

  2. 线程安全会集(举个例子ConcurrentDictionary)就完全差别了。与不可变集结分化,线程安 全集结是足以修改的。线程安全集结本身就隐含了独具的同步效率

  3. 至于锁的应用,有四条第一的准则

  • 限定锁的成效范围(比如把lock语句使用的指标设为私有成员)
  • 文书档案中写清锁的遵循内容
  • 锁范围内的代码尽量少(锁定时决不开展围堵操作)
  • 在调节锁的时候不要运营随便的代码(不要在讲话中调用事件管理,调用虚构方法,调用委托)
  1. 一旦急需异步锁,请尝试 SemaphoreSlim

  2. 毫不在 ASP. NET 中采取 Task.Run,那是因为在 ASP.NET 中,管理央求的代码本来正是在线程池线程中运作的,强行把它内置另叁个线程池线程常常会差强人意

(7) 实用手艺

  1. 前后相继的八个部分共享了一个财富,未来要在首先次访谈该财富时对它开端化
static int _simpleValue;

static readonly Lazy<Task<int>> MySharedAsyncInteger = 
    new Lazy<Task<int>>(() => 
    Task.Run(async () =>
        {
            await Task.Delay(TimeSpan.FromSeconds(2));

            return _simpleValue  ;
        }));

async Task GetSharedIntegerAsync()
{
    int sharedValue = await MySharedAsyncInteger.Value;
}
  class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("当前线程{0},当前状态{1}", Thread.CurrentThread.GetHashCode(), Thread.CurrentThread.ThreadState);
            //使用线程池创建线程,然后取消线程
            CancelWithThreadPoolMiniSnippet();
        }
        static CancellationTokenSource cts = new CancellationTokenSource();
        static CancellationToken token = cts.Token;
        static void CancelWithThreadPoolMiniSnippet()
        {
            Console.WriteLine("当前线程{0},当前状态{1}", Thread.CurrentThread.GetHashCode(), Thread.CurrentThread.ThreadState);

            #region 使用QueueUserWorkItem的构造函数,传递cts.Token,但我不喜欢这个模式 跟踪不了状态
            //ThreadPool.QueueUserWorkItem(new WaitCallback(DoSomeWork), ctn);
            #endregion

            #region 使用传递参数的模式 传递CancellationToken,这里的cts.Token是作为Action的参数传递的
            //var action = new Action<object>(DoSomeWork);
            //Task t = new Task(action, ctn);
            //t.Start();
            //Console.WriteLine("开始,当前线程{0},当前状态{1}", t.GetHashCode(), t.Status);
            #endregion

            #region 使用Task的构造函数,传递cts.Token,但CancellationTokenSource要弄成全局变量,否则方法找不到,就取消不了。
            //Task t = new Task(Work, cts.Token);
            //t.Start();
            #endregion

            #region 注册回调函数,当CancellationTokenSource.Cancel()执行后,调用回调函数 
            token.Register(CallBack, true);  //注册回调函数
            Task t = new Task(Work);
            t.Start();
            #endregion

            Thread.SpinWait(5000000);

            cts.Cancel();
            Console.WriteLine("结束,当前线程{0},当前状态{1}", t.GetHashCode(), t.Status);
            Console.Read();
        }


        static void DoSomeWork(object obj)
        {
            CancellationToken token = (CancellationToken)obj;
            for (int i = 0; i < 100000; i  )
            {
                Console.WriteLine(i);
                // Simulating work.
                //Thread.SpinWait(5000000);

                if (token.IsCancellationRequested)
                {

                    break;
                }
            }
        }


        static void Work()
        {

            for (int i = 0; i < 100000; i  )
            {
                Console.WriteLine(i);
                if (token.IsCancellationRequested)
                {

                    break;
                }
            }
        }

        static void CallBack()
        {

            Console.WriteLine("I'm call back!"   );
        }
    }

(3)并行开采的基本功

  1. Parallel 类有一个简练的分子 Invoke,可用来需求并行调用一堆措施,何况那个主意(大多数)是相互独立的
static void ProcessArray(double[] array)
{
    Parallel.Invoke(
    () => ProcessPartialArray(array, 0, array.Length / 2),
    () => ProcessPartialArray(array, array.Length / 2,array.Length));
}

static void ProcessPartialArray(double[] array, int begin, int end)
{
    // 计算密集型的处理过程 ...  
}
  1. 在产出编制程序中,Task类有七个职能:作为并行任务,或当做异步义务。并行职分能够接纳阻塞的成员函数,譬如 Task.Wait、Task.Result、Task.WaitAll 和 Task.WaitAny。并行义务平常也选拔 AttachedToParent 来确立义务之间的“父 / 子”关系。并行职分的创造须求 用 Task.Run 或许Task.Factory.StartNew。
  2. 反而的,异步任务应该制止选用阻塞的分子函数,而应当利用 await、Task.WhenAll 和 Task. WhenAny。异步义务不利用 AttachedToParent,但足以因此 await 另二个职务,创立一种隐 式的“父 / 子”关系。

代码内施行结果如下,该结果为CancellationToken的回调函数应用:

(4)测量检验手艺

  1. MSTest从Visual Studio二零一三 版本开头支持 async Task 类型的单元测验
  2. 只要单元测量检验框架不扶持 async Task 类型的单元测量检验,就需求做一些极度的改造本事等待异步操作。此中一种做法是运用 Task.Wait,并在有荒唐时拆开 AggregateException 对象。笔者的提议是行使 NuGet 包 Nito.AsyncEx 中的 AsyncContext 类

那边附上一个ABP中落实的可操作AsyncHelper类,正是基于AsyncContext达成

    /// <summary>
    /// Provides some helper methods to work with async methods.
    /// </summary>
    public static class AsyncHelper
    {
        /// <summary>
        /// Checks if given method is an async method.
        /// </summary>
        /// <param name="method">A method to check</param>
        public static bool IsAsyncMethod(MethodInfo method)
        {
            return (
                method.ReturnType == typeof(Task) ||
                (method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))
                );
        }

        /// <summary>
        /// Runs a async method synchronously.
        /// </summary>
        /// <param name="func">A function that returns a result</param>
        /// <typeparam name="TResult">Result type</typeparam>
        /// <returns>Result of the async operation</returns>
        public static TResult RunSync<TResult>(Func<Task<TResult>> func)
        {
            return AsyncContext.Run(func);
        }

        /// <summary>
        /// Runs a async method synchronously.
        /// </summary>
        /// <param name="action">An async action</param>
        public static void RunSync(Func<Task> action)
        {
            AsyncContext.Run(action);
        }
    }
  1. 在 async 代码中,关键法则之一正是制止使用 async void。作者可怜建议我们在对 async void 方法做单元测验时张开代码重构,并不是接纳 AsyncContext。

在NET Framework4.6里,微软提供了async和await语法,也可能有关线程安全,作者将会在新的语法相关小说里上课async和await的用法。

  • 1.前言
  • 2.言无不尽
  • 3.支出条件和核心
    • (1)并发编制程序概述
    • (2)异步编制程序基础
    • (3)并行开采的基本功
    • (4)测量检验技艺
    • (5)集合
    • (6)函数式OOP
    • (7)同步

到此NET Framework4.0里的线程安全就都说完了。。。。。。。

2.直言不讳

长久以来都有一种意见是落到实处底层架构,编写驱动和内燃机,或许是框架和工具开垦的才是尖端开垦职员,做上层应用的人唯有是“码农”,其实能够利用好平台提供的相干类库,实际不是一体选择底层技能和好达成,开采出高水平,稳定的应用程序,对本领技术的考验并不低于开荒底层库,如TPL,async,await等。

 

(6)函数式OOP

  1. 异步编制程序是函数式的(functional),.NET 引进的async让开荒者进行异步编制程序的时候也能用进程式编制程序的思辨来开展考虑,可是在里面贯彻上,异步编程还是是函数式的

    宏伟说过,世界既是进程式的,也是函数式的,可是究竟是函数式的

  2. 可以用await等待的是叁个类(如Task对象),并不是多少个措施。能够用await等待有些方法再次回到的Task,无论它是或不是async方法。

  3. 类的构造函数里是无法举办异步操作的,平常能够行使如下方法。相应的,大家得以透过var instance=new Program.CreateAsync();

    class Program
    {
        private Program()
        {

        }

        private async Task<Program> InitializeAsync()
        {
            await Task.Delay(TimeSpan.FromSeconds(1));

            return this;
        }

        public static Task<Program> CreateAsync()
        {
            var result = new Program();

            return result.InitializeAsync();
        }

    }
  1. 在编写制定异步事件处理器时,事件参数类最棒是线程安全的。要到位这一点,最轻便易行的办法便是让它成为不可变的(即把全体的本性都设为只读)

那是线程安全的末尾一篇了,首要介绍CancellationToken的各类行使。

(2)异步编制程序基础

  1. 指数退避是一种重试计策,重试的延迟时间会逐 次扩展。在拜会 Web 服务时,最棒的主意便是选用指数退避,它能够堤防服务器被太多的重试阻塞
static async Task<string> DownloadStringWithRetries(string uri)
{
    using (var client = new HttpClient())
    {
        // 第 1 次重试前等 1 秒,第 2 次等 2 秒,第 3 次等 4 秒。
        var nextDelay = TimeSpan.FromSeconds(1);
        for (int i = 0; i != 3;   i)
        {
            try
            {
                return await client.GetStringAsync(uri);
            }
            catch
            { }

            await Task.Delay(nextDelay);
            nextDelay = nextDelay   nextDelay;
        }

        // 最后重试一次,以便让调用者知道出错信息。
        return await client.GetStringAsync(uri);
    }
}
  1. Task.Delay 切合用来对异步代码实行单元测验或许达成重试逻辑。要促成超时成效的话, 最佳利用 CancellationToken
  2. 如何落成一个富有异步签名的一块方法。如若从异步接口或基类承接代码,但希望用联合的章程来贯彻它,就能够油但是生这种景色。消除办法是足以选择Task.FromResult 方法创立并回到一个新的 Task 对象,这一个 Task 对象是早就 实现的,并有钦点的值
  3. 动用 IProgress 和 Progress 类型。编写的 async 方法必要有 IProgress 参数,其 中 T 是索要报告的快慢类型,能够突显操作的快慢
  4. Task.WhenALl能够等待全数职分到位,而当每一个Task抛出十分时,可以选拔性捕获非常
  5. Task.WhenAny能够等待任一职责到位,使用它尽管能够变成超时职责(在那之中叁个Task设为Task.Delay),然而显明用特其余包罗撤除标识的逾期函数管理相比较好
  6. 第一章提到async和上下文的标题:在私下认可情形下,一个 async 方法在被 await 调用后回复运营时,会在本来的上下文中运作。而丰硕扩展方法ConfigureAwait(false)后,则会在await之后抛弃上下文

图片 1

(1)并发编制程序概述

  1. 并发:同期做多件业务
  2. 三十二线程:并发的一种样式,它利用三个线程来进行顺序
  3. 并行管理:把正在执行的大方的义务分割成小块,分配给多个同期运营的线程
  4. 并行管理是二十四线程的一种,而十六线程是出新的一种管理情势
  5. 异步编制程序:并发的一种样式,它使用future情势或然callback机制,以幸免产生不须要的线程
  6. 异步编制程序的核激情念是异步操作:运转了的操作会在一段时间后实现。这一个操作正在实行时,不会堵塞原来的线程。运行了那个操作的线程,可以继续施行其余职分。当操作达成后,会文告它的future,大概调用回调函数,以便让程序知道操作已经结束
  7. await关键字的效应:运营贰个将会被试行的Task(该Task将要新线程中运作),并及时回去,所以await所在的函数不会被封堵。当Task达成后,继续执行await前面包车型大巴代码
  8. 响应式编程:并发的一种基于注明的编制程序情势,程序在该情势中对事件作出反应
  9. 不用用 void 作为 async 方法的回来类型! async 方法能够回来 void,不过这只限于编写事件管理程序。一个平日的 async 方法如果未有再次回到值,要回去 Task,实际不是 void
  10. async 方法在初步时以协同方式推行。在 async 方法内部,await 关键字对它的参数试行二个异步等待。它首先检查操作是不是已经产生,假若产生了,就持续运营(同步情势)。不然,它会半涂而废 async 方法,并重回,留下叁个未到位的 task。一段时间后, 操作完成,async
    艺术就过来运转。
  11. await代码中抛出十分后,极度会沿着Task方向前进到引用处
  12. 你一旦在代码中利用了异步,最佳一向利用。调用 异步方法时,应该(在调用甘休时)用 await 等待它回到的 task 对象。必定要防止使用 Task.Wait 或 Task.Result 方法,因为它们会促成死锁
  13. 线程是叁个单身的周转单元,每一种进度之中有四个线程,每一种线程可以独家同期进行命令。 每一种线程有温馨单独的栈,可是与经过内的其余线程分享内存
  14. 各样.NET应用程序都维护着八个线程池,这种状态下,应用程序差相当的少没有要求活动创制新的线程。你若要为 COM interop 程序创设 SAT 线程,就得 创立线程,那是天下无敌须要线程的境况
  15. 线程是低端其余肤浅,线程池是不怎么高端一点的虚幻
  16. 并发编制程序用到的聚众有两类:并发造成 不可变会集
  17. 大部分产出编制程序技艺都有一个类似点:它们本质上都以函数式的。这里的函数式是用作一种基于函数组合的编制程序格局。函数式的二个编制程序原则是简单(幸免副功效),另二个是不变性(指一段数据不能够被涂改)
  18. .NET 4.0 引进了相互义务库(TPL),完全援救数据交互和职务并行。不过一些能源少之甚少的 平台(譬喻手提式有线电话机),平常不扶助 TPL。TPL 是 .NET 框架自带的

虽说第一篇文章是二〇一二年,尽管历时近三年,但请相信自个儿,代码早在七年前就曾经写完呀。只是作者直接平素向来没配文字发出来。。。。。。

1,ThreadPool直接开发银行线程,传递CancellationToken。

不然那线程安全的小说恐怕还要拖。。。。。。。。哈哈


话相当少说,请看代码。

注:此小说为原创,迎接转发,请在篇章页面显然地点给出此文链接!
若你以为那篇小说还不错请点击下右下角的推荐,特别多谢!

3,CancellationToken的回调函数应用。

本文由彩世界开奖app官网发布于计算机编程,转载请注明出处:C#线程安全使用(五)

关键词: C# .NET 读书笔记