c# 高并发的几种方式(六)

357 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第29天,点击查看活动详情 

到目前位置,我们一共介绍了5中block

  • bufferblock 基础的block
  • actionblock 简单消费block,可以再构造中实现委托处理数据
  • tansformblock 用来做数据转换,一个inputqueue,一个outputqueue
  • tansformmanyblock,一个inputqueue的数据,可以放置多个数据进入outputqueue
  • boradcastblock,广播block 下面我们继续介绍几个block

writeonceblock

一次写入block,这个block类似硬件的otp了。它最多只能存储一个数据,一旦这个数据被发送出去以后,这个数据还是会留在Block中,但不会被删除或被新来的数据替换,同样所有的接收者都会收到这个数据的备份。

demo

为了清晰的了解这个demo,我们把前面的广播demo拿过来,稍加改动,看看结果

        static WriteOnceBlock<int> bb = new WriteOnceBlock<int>((i) => { return i; });
        /// <summary>
        /// 广播
        /// </summary>
        //static BroadcastBlock<int> bb = new BroadcastBlock<int>((i) => { return i; });
        /// <summary>

结果

image.png

可以看到,我们写入0以后,之后的数据无法写入。

batchblock

该block其实和transformmanyblock可以对比说。
transformmanyblock是可以接收一个数据,放多个数据到output中
batchblock是接收多个数据,满足数量后,放置一个结合体数据到output中

demo

using System;
using System.Threading.Tasks.Dataflow;
using System.Threading.Tasks;
using System.Threading;
using System.Net;

namespace DataFlowDemoS
{
    internal class Program
    {
        /// <summary>
        /// 构造
        /// </summary>
        static BatchBlock<int> bb = new BatchBlock<int>(3);
        /// <summary>
        /// 消费
        /// </summary>
        static ActionBlock<int[]> ab = new ActionBlock<int[]>((i) =>
        {
            string s = string.Empty;
            foreach (int m in i)
            {
                s += m + " ";
            }
            Console.WriteLine(s);
        });
        /// <summary>
        /// 生产
        /// </summary>
        static void TestSync()
        {
            bb.LinkTo(ab);

            for (int i = 0; i < 10; i++)
            {
                bb.Post(i);
            }
            bb.Complete();
        }
        /// <summary>
        /// main
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            Console.WriteLine("Here We Go!");
            TestSync();
            Console.ReadLine();
        }
    }
}

效果

image.png

joinblock

joinblock可以看作是batchblock的升级版本。

  • batchblock是从一个sourceblock中接收多个数据
  • joinblock是从多个sourceblock中接收一个组合数据

demo

using System;
using System.Threading.Tasks.Dataflow;
using System.Threading.Tasks;
using System.Threading;
using System.Net;

namespace DataFlowDemoS
{
    internal class Program
    {
        /// <summary>
        /// 构造
        /// </summary>
        static JoinBlock<int, string> jb = new JoinBlock<int, string>();
        /// <summary>
        /// 消费
        /// </summary>
        static ActionBlock<Tuple<int, string>> ab = new ActionBlock<Tuple<int, string>>((i) =>
        {
            Console.WriteLine(i.Item1 + " " + i.Item2);
        });
        /// <summary>
        /// 生产
        /// </summary>
        static void TestSync()
        {
            jb.LinkTo(ab);

            for (int i = 0; i < 5; i++)
            {
                jb.Target1.Post(i);
            }
            Console.WriteLine("Init Post Over");
            for (int i = 5; i > 0; i--)
            {
                Thread.Sleep(1000);
                jb.Target2.Post(i.ToString());
            }
            Console.WriteLine("String Post Over");
        }
        /// <summary>
        /// main
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            Console.WriteLine("Here We Go!");
            TestSync();
            Console.ReadLine();
        }
    }
}

效果

image.png

从上面的demo中,我们可以看到。
当int的数据post完毕,joinblock并没有输出,当string开始post后,block才开始输出数据。
joinblock只有当两个sourceblock都有数据,满足条件的时候、才会触发动作。

batchjoinblock

这个名字起的简洁明了,不用我多讲,这个block是batch和join的组合体。具备两者的特质。
上demo

demo

using System;
using System.Threading.Tasks.Dataflow;
using System.Threading.Tasks;
using System.Threading;
using System.Net;
using System.Collections.Generic;

namespace DataFlowDemoS
{
    internal class Program
    {
        /// <summary>
        /// 构造
        /// </summary>
        static BatchedJoinBlock<int, string> bjb = new BatchedJoinBlock<int, string>(3);
        /// <summary>
        /// 消费
        /// </summary>
        static ActionBlock<Tuple<IList<int>, IList<string>>> ab = new ActionBlock<Tuple<IList<int>, IList<string>>>((i) =>
        {
            Console.WriteLine("-----------------------------");
            foreach (int m in i.Item1)
            {
                Console.WriteLine(m);
            };
            foreach (string s in i.Item2)
            {
                Console.WriteLine(s);
            };
        });
        /// <summary>
        /// 生产
        /// </summary>
        static void TestSync()
        {
            bjb.LinkTo(ab);

            for (int i = 0; i < 5; i++)
            {
                bjb.Target1.Post(i);
            }
            Console.WriteLine("Int Post Over");
            for (int i = 5; i > 0; i--)
            {
                bjb.Target2.Post(i.ToString());
            }
            Console.WriteLine("String Post Over");
        }
        /// <summary>
        /// main
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            Console.WriteLine("Here We Go!");
            TestSync();
            Console.ReadLine();
        }
    }
}

效果

image.png

小结

OK,到此为止我们已经介绍完了全部的9种block。简单的罗列:

  • bufferblock
  • actionblock
  • tansformblock
  • tansformmanyblock
  • boradcastblock
  • writeoneceblock
  • batchblock
  • joinblock
  • batchjoinblock