C#并行编程之Task任务

任务,基于线程池。其使我们对并行编程变得更简单,且不用关心底层是怎么实现的。
System.Threading.Tasks.Task类是Task Programming Library(TPL)中最核心的一个类。

一、任务与线程

1:任务是架构在线程之上的,也就是说任务最终还是要抛给线程去执行。

2:任务跟线程不是一对一的关系,比如开10个任务并不是说会开10个线程,这一点任务有点类似线程池,但是任务相比线程池有很小的开销和精确的控制。

我们用VS里面的“并行任务”看一看,快捷键Ctrl+D,K,或者找到“调试"->"窗口“->"并行任务“,我们在WaitAll方法处插入一个断点,最终我们发现任务确实托管给了线程。

二、初识Task

两种构建Task的方式,只是StartNew方法直接构建出了一个Task之后又调用了其Start方法。

    Task.Factory.StartNew (() =>
    {
        Console.WriteLine("Hello word!");
    });

    Task task =
    new Task
    (() =>
    {
        Console.WriteLine("Hello,Word!");
    });
    task.Start();

在Task内部执行的内容我们称作为Task的Body,Task提供了多个初始化重载的方法。

public Task(Action action);
public Task(Action<object> action,
object state
);给action传参数
public Task(Action action, CancellationToken cancellationToken);
public Task(Action action, TaskCreationOptions creationOptions);

例如使用了重载方法的State参数:

Task task2 = new Task((obj ) =>
{
    Console.WriteLine("Message: {0}", obj); }, "Say \"Hello\" from task2");
    task2.Start();
}

补充细节

在创建Task的时候,Task有很多的构造函数的重载,一个主要的重载就是传入TaskCreateOptions的枚举:

  • TaskCreateOptions.None:用默认的方式创建一个Task
  • TaskCreateOptions.PreferFairness:请求scheduler尽量公平的执行Task(后续文章会将是,Task和线程一样,有优先级的)
  • TaskCreateOptions.LongRunning:声明Task将会长时间的运行。
  • TaskCreateOptions.AttachToParent:因为Task是可以嵌套的,所以这个枚举就是把一个子task附加到一个父task中。

三、任务的结果

任务结束时,它可以把一些有用的状态信总写到共享对象中。这个共享对象必须是线程安全的。 
另一个方式是使用返回某个结果的任务。使用Task类的泛型版本,就可以定义返冋某个结果的任务的返回类型。

使用返回值的Result属性可获取是在一个Task运行完成才会获取的,所以task2是在task1运行完成后,才开始运行,也就是说上面的两个result的值不管运行多少次都是不会变的。其中我们也可以通过CurrentId来获取当前运行的Task的编号。

    var loop = 0;
    var task1 = new Task<int>(() =>
    {
        for (var i = 0; i < 1000; i++)
            loop += i;
        return loop;
    });
    task1.Start();
    var loopResut = task1.Result;

    var task2 = new Task<long>(obj=>
    {
        long res = 0;
        var looptimes = (int)obj;
        for (var i = 0; i < looptimes; i++)
            res += i;
        return res;
    },loopResut);

    task2.Start();
    var resultTask2 = task2.Result;

    Console.WriteLine("任务1的结果':{0}\n任务2的结果:{1}",   loopResut,resultTask2);

.NET 4.5 :Task.Run

在 .NET Framework 4.5 及更高版本(包括 .NET Core 和 .NET Standard)中,使用静态 Task.Run 方法作为 TaskFactory.StartNew 的快捷方式。

Task.Run的跟Task.Factory.StarNew和new Task相差不多,不同的是前两种是放进线程池立即执行,而Task.Run则是等线程池空闲后在执行。

Run方法只接受无参的Action和Func委托,另外两个接受一个object类型的参数。

在msdn中TaskFactory.StartNew的备注信息如下:

四、连续任务

所谓的延续的Task就是在第一个Task完成后自动启动下一个Task。我们通过ContinueWith方法来创建延续的Task。我们假设有一个接受xml解析的服务,首先从某个地方接受文件,然后解析入库,最后发送是否解析正确的回执。在每次调用ContinueWith方法时,每次会把上次Task的引用传入进来,以便检测上次Task的状态,比如我们可以使用上次Task的Result属性来获取返回值。

    var ReceiveTask  = new Task(() => ReceiveXml());
    var ResolveTask = ReceiveTask .ContinueWith <bool>((r) => ResolveXml());
    var SendFeedBackTask = ResolveTask.ContinueWith <string>((s) => SendFeedBack(s.Result));
    ReceiveTask.Start();
    Console.WriteLine(SendFeedBackTask.Result);

上面的代码我们也可以这么写:

   var SendFeedBackTask = Task.Factory.StartNew(() => ReceiveXml())
        .ContinueWith<bool>(s => ResolveXml())
        .ContinueWith<string>(r => SendFeedBack(r.Result));
    Console.WriteLine(SendFeedBackTask.Result);

无论前一个任务是如何结束的,前面的连续任务总是在前一个任务结束时启动。使用 TaskContinuationOptions枚举中的值,可以指定,连续任务只有在起始任务成功(或失败)结束吋启动。可能的值是 OnlyOnFaulted、NotOoFaulted、Onl)OnCanceIed、NotOnCanceled 和 OnlyOnRanToCompletion

Task t5 = t1.ContinueWith(DoOnError,
TaskContinuationOptions.OnlyOnFaulted);

五、分离嵌套任务

有些情况下我们需要创建嵌套的Task,嵌套里面又分为分离的和不分离的。其创建的方式很简单,就是在Task的body里面创建一个新的Task。如果新的Task未指定AttachedToParent选项,那么就是分离嵌套的。我们看下面这段代码。下面的代码中outTask.Wait()表示等待outTask执行完成。

var outTask = Task.Factory.StartNew(() =>
{
    Console.WriteLine("Outer task beginning...");
    var childTask = Task.Factory.StartNew(() =>
    {
        Thread.SpinWait(3000000);
        Console.WriteLine("Detached nested task completed.");
    });
});
outTask.Wait();
Console.WriteLine("Outer task completed.");
Console.ReadKey();

我们可以看到运行结果是:

六、子任务

我们将上面的代码加上TaskCreationOptions选项:

如果父任务在子任务之前结束,父任务的状态就显示为WaitingForChildrenToComplete。只要子任务也结束时,父任务的状态就变成RanToCompletion。.、当然,如果父任务用TaskCreatiooOptions 枚举中的DetachedFromParent创建子任务时,这就无效。

var outTask = Task.Factory.StartNew(() =>
{
    Console.WriteLine("Outer task beginning...");
    var childTask = Task.Factory.StartNew(() =>
    {
        Thread.SpinWait(3000000);
        Console.WriteLine("Detached nested task completed.");
    },TaskCreationOptions.AttachedToParent);
});
outTask.Wait();
Console.WriteLine("Outer task completed.");

看到运行结果:

七、取消任务

在4.0中给我们提供一个“取消标记”叫做CancellationTokenSource.Token,在创建task的时候传入此参数,就可以将主线程和任务相关联。我们通过cancellation的tokens来取消一个Task。

有点要特别注意的,当我们调用了Cancel()方法之后,.NET Framework不会强制性的去关闭运行的Task。我们自己必须去检测之前在创建Task时候传入的那个CancellationToken。

一旦cancel被调用,task将会抛出OperationCanceledException来中断此任务的执行,最后将当前task的Status的IsCanceled属性设为true。

1、在很多Task的Body里面包含循环,我们可以在轮询的时候判断IsCancellationRequested属性是否为True,如果是True的话,就可以停止循环以及释放资源,同时抛出OperationCanceledException异常出来。

2、或者在任务中设置“取消信号“叫做ThrowIfCancellationRequested,来等待主线程使用Cancel来通知。

3、检测task是否被cancel就是调用CancellationToken.WaitHandle属性。CancellationToken的WaitOne()方法会阻止task的运行,只有CancellationToken的cancel()方法被调用后,这种阻止才会释放。

var cts = new CancellationTokenSource();

var ct =  cts.Token;

var task = Task.Factory.StartNew(() =>
{
    for (var i = 0; i < 10000000; i++)
    {
        if (ct.IsCancellationRequested)
        {
            Console.WriteLine("任务开始取消...");
            throw new OperationCanceledException(ct);
        }
         //或者直接在检测到异常时,扔出异常:  token.ThrowIfCancellationRequested();
         //或者等待 WaitHandle:           token.WaitHandle.WaitOne();

    }
},ct);//传入CancellationToken作为Task第二个参数

ct.Register(() =>
{
    Console.WriteLine("已经取消");
});

Thread.Sleep(5000);
cts.Cancel();//如果想要取消一个Task的运行,只要调用CancellationToken实例的Cancel()方法就可以了。

try
{
    task.Wait();
}
catch (AggregateException e)
{
    foreach (var v in e.InnerExceptions)
        Console.WriteLine("msg: " + v.Message);
}

八、休眠:等待时间执行

在TPL中我们可以通过三种方式进行等待,一是通过CancellTaken的WaitHanle进行等待、第二种则是通过传统的Tread.Sleep方法、第三种则通过Thread.SpainWait方法。

1、CancellToken方式:每次我们等待十秒钟之后,再进行下次输出。

有一点要注意:WaitOne()方法只有在设定的时间间隔到了,或者Cancel方法被调用,此时task才会被唤醒。如果如果cancel()方法被调用而导致task被唤醒,那么CancellationToken.WaitHandle.WaitOne()方法就会返回true,如果是因为设定的时间到了而导致task唤醒,那么CancellationToken.WaitHandle.WaitOne()方法返回false。

    var cts = new CancellationTokenSource();
    var ct = cts.Token;

    var task = new Task(() =>
    {
        for (var i = 0; i < 100000; i++)
        {
            var cancelled = ct.WaitHandle.WaitOne(1000 );
            Console.WriteLine(" {0}. Cancelled? {1}", i, cancelled);
            if (cancelled)
            {
                throw new OperationCanceledException(ct);
            }
        }
    }, ct);
    task.Start();

2、上面的功能如果我们要是通过Tread.Sleep方式实现:

            var task = new Task(() =>
            {
                for (var i = 0; i < 100000; i++)
                {
                    Thread.Sleep(10000);
                    var cancelled =ct.IsCancellationRequested;
                    Console.WriteLine(" {0}. Cancelled? {1}",
                                i, cancelled); if (cancelled)
                    {
                        throw new OperationCanceledException(ct);
                    }
                }
            },ct);

3、Thread.SpainWait则跟上面两种方式完全不同,上面的两种方式都是会在线程调度程序不考虑改线程,直等到运行结束。而Thread.SpainWait的作用实质上会将处理器置于十分紧密的循环中,主要的作用是来实现同步锁的作用。并不常用,大部分情况下我们可以通过Lock的方式来实现。

Thread.SpinWait(10000);

九、等待任务执行

在很多时候我们也许需要等待同时开启的几个线程完成之后再来做其他事,在TPL中提供了几种方式来等待任务执行。Task.Wait等待单个任务完成;Task.WaitAll等待所有的Task完成、TaskAny等在其中的任何一个或则多个任务完成。

1、Task.Wait: 等待单独的一个Task执行完成

共有5个重载:Wait()、Wait(CancellToken)、Wait(Int32)、Wait(TimeSpan)、Wait(TimeSpan、CancellToken)。各个重载方法的含义:

  • 1)Wait():等待整个任务完成或者取消或者出现异常;
  • 2)Wait(CancellToken):等待任务直到CancellToken调用取消或者完成,或者出现异常;
  • 3)Wait(Int32):等待任务,未完成则到指定的时间;
  • 4)Wait(TimeSpan):同上;
  • 5)Wait(TimeSpan、CancellToken):等待任务到指定时间,或者CancellToken调用取消或者任务完成。
static void Main(string[] args)
{
    var tokenSource = new CancellationTokenSource();
    CancellationToken token = tokenSource.Token;
        Task task = createTask(token,6);    task.Start();
    Console.WriteLine("Wait() complete.");
    task.Wait();
    Console.WriteLine("Task Completed.");

    task = createTask(token,3);
    task.Start();
    Console.WriteLine("Wait(2) secs for task to complete.");
    bool completed = task.Wait(2000);
    Console.WriteLine("Wait ended - task completed: {0}", completed);

    task = createTask(token,4);
    task.Start();
    Console.WriteLine("Wait(2,token) for task to complete.");
    completed = task.Wait(2000, token);
    Console.WriteLine("Wait ended - task completed: {0} task cancelled {1}",
    completed, task.IsCanceled);
    Console.WriteLine("Main method complete. Press enter to finish.");
    Console.ReadLine();
}
static Task createTask(CancellationToken token,int loop)
{
    return new Task(() =>
    {
        for (int i = 0; i < loop; i++)
        {
            token.ThrowIfCancellationRequested();
            Console.WriteLine("Task - Int value {0}", i);
            token.WaitHandle.WaitOne(1000);
        }
    }, token);
}

循环都会等待1秒钟,这样我们可以看看Wait(2000)的效果,看看运行后的效果:

从上面的例子可以看出,wait方法子task执行完成之后会返回true。
注意:当在执行的task内部抛出了异常之后,这个异常在调用wait方法时会被再次抛出。后面再"异常处理篇"会讲述。

2、Task.WaitAll方法: 等待多个task

是等待所有的任务完成,也有5个重载, 也可以传递时间以及Token参数,进行等待时间以及取消Token的控制。

   var tokenSource = new CancellationTokenSource();
    CancellationToken token = tokenSource.Token;
    var task1 = createTask(token,2);
    var task2 = createTask(token, 5);
    task1.Start();
    task2.Start();
    Console.WriteLine("Waiting for tasks to complete.");
    Task.WaitAll(task1, task2);
    Console.WriteLine("Tasks Completed.");

注意:如果在等在的多个task之中,有一个task抛出了异常,那么调用WaitAll()方法时就会抛出异常。

ContinueWith结合WaitAll来玩一把

当这两者结合起来,我们就可以玩一些复杂一点的东西,比如说现在有4个任务,其中t1需要串行,t2-t3可以并行,t4需要串行.

ConcurrentStack<int> stack = new ConcurrentStack<int>();

//t1先执行
var t1 = Task.Factory.StartNew(() =>
{
    stack.Push(1);
    stack.Push(2);
});

//t2,t3并行执行
var t2 = t1.
ContinueWith
(t =>
{
    int result;

    stack.TryPop(out result);
});

//t2,t3并行执行
var t3 = t1.
ContinueWith
(t =>
{
    int result;

    stack.TryPop(out result);
});

//等待t2和t3执行完
Task.WaitAll(t2, t3);

 //t4z再执行
var t4 = Task.Factory.StartNew(() =>
{
    Console.WriteLine("当前集合元素个数:" + stack.Count);
});

3、Task.WaitAny

等待任何一个任务完成,完成之后返回其完成的任务的Index:

    var tokenSource = new CancellationTokenSource();
    CancellationToken token = tokenSource.Token;
    var task1 = createTask(token,2);
    var task2 = createTask(token, 5);
    task1.Start();
    task2.Start();
    Console.WriteLine("Waiting for tasks to complete.");
    var index = Task.WaitAny(task1, task2);
    Console.WriteLine("Tasks Completed.Index is {0}",index);

十、异常处理

在TPL中,异常的触发器主要是这几个:
Task.Wait(), Task.WaitAll(), Task,WaitAny(),Task.Result。而在TPL出现的异常都会以AggregateException的示例抛出,我们在进行基本的异常处理时,可以通过查看AggregateException的InnerExceptions来进行内部异常的捕获:

var tokenSource = new CancellationTokenSource();
    var token = tokenSource.Token;
    var task1 = new Task(() =>
    {
        throw new NullReferenceException() {
Source
="task1"};
    });
    var task2 = new Task(() =>
    {
        throw new ArgumentNullException("a", "a para can not be null") { Source="task2"};
    });
    task1.Start(); task2.Start();
    try
    {
        Task.WaitAll(task1, task2);
    }
    catch(AggregateException ex)
    {
        foreach (Exception inner in ex.InnerExceptions)
        {
            Console.WriteLine("Exception type {0} from {1}",
            inner.GetType(), inner.Source);
        }
    }

同时,我们还可以通过Task的几个属性来判断Task的状态,如:IsCompleted, IsFaulted, IsCancelled,Exception。

另外,AggregateException中还提供了Handle方法来给我们方法来给我们处理每个内部 异常,每个异常发生时都会调用Handle传入的delegate ,同时我们需要通过返回True,False来告诉异常是否已经被处理,比如对于OperationCanceledException我们知道是取消了Task,是肯定可以处理的:

    try
    {
        Task.WaitAll(task1, task2, task3, task4);
    }
    catch(AggregateException ex)
    {
        ex.Handle((e) =>
        {
            if (e is OperationCanceledException)
            {
                return true;
            }
            else
            {
                return false;
            }
        });
    }

十一、执行晚加载的Task(Lazily Task)

晚加载,或者又名延迟初始化,主要的好处就是避免不必要的系统开销。在并行编程中,可以联合使用Lazy变量和Task<>.Factory.StartNew()做到这点。(Lazy变量时.NET 4中的一个新特性,这里大家不用知道Lazy的具体细节)。

Lazy变量只有在用到的时候才会被初始化。所以我们可以把Lazy变量和task的创建结合:只有这个task要被执行的时候才去初始化。

            // do the same thing in a single statement
            Lazy<Task<string>> lazyData2 = new Lazy<Task<string>>(
            () => Task<string>.Factory.StartNew(() =>
            {
                Console.WriteLine("Task body working...");
                return "Task Result";
            }));

            Console.WriteLine("Calling second lazy variable");
            Console.WriteLine("Result from task: {0}", lazyData2.Value.Result);

首先我们回想一下,在之前的系列文章中我们是怎么定义一个task的:直接new,或者通过task的factory来创建,因为创建task的代码是在main函数中的,所以只要new了一个task,那么这个task就被初始化。现在如果用了Lazy的task,那么现在我们初始化的就是那个Lazy变量了,而没有初始化task,(初始化Lazy变量的开销小于初始化task),只有当调用了lazyData.Value时,Lazy变量中包含的那个task才会初始化。

到此这篇关于C#并行编程之Task任务的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • C#利用Task实现任务超时多任务一起执行的方法

    前言 其实Task跟线程池ThreadPool的功能类似,不过写起来更为简单,直观.代码更简洁了,使用Task来进行操作.可以跟线程一样可以轻松的对执行的方法进行控制. 创建Task有两种方式,一种是使用构造函数创建,另一种是使用 Task.Factory.StartNew 进行创建. 如下代码所示 1.使用构造函数创建Task Task t1 = new Task(MyMethod); 2.使用Task.Factory.StartNew 进行创建Task Task t1 = Task.Fact

  • C#中Thread(线程)和Task(任务)实例详解

    目录 线程 一,使用Thread类启动线程和数据传输 二,线程池ThreadPool类 任务 一,创建并启动任务 二,连续任务 三,资源冲突问题 总结 线程 线程:对于所有需要等待的操作,例如移动文件,数据库和网络访问都需要一定的时间,此时就可以启动一个新的线程,同时完成其他任务.一个进程的多个线程可以同时运行在不同的CPU上或多核CPU的不同内核上. 一个应用程序启动时,会启动一个进程(应用程序的载体),然后进程会启动多个线程. 一,使用Thread类启动线程和数据传输 使用Thread类可以

  • C#中Task.ContinueWith连续任务使用实例

    通过任务,可以指定在任务完成之后,应开始运行之后另一个特定任务.例如,一个使用前一个任务的结果的新任务,如果前一个任务失败了,这个任务就应执行一些清理工作.任务处理程序都不带参数或者带一个对象参数,而任务的连续处理方法都有一个Task类型的参数,这里可以访问起始任务的相关信息: 如下面的示例代码:   class Program     {         static void DoOnFirst()         {             Console.WriteLine($"doin

  • C#使用Task.ContinueWith组合任务

    代码案例 简单Demo 代码: public static void Main() { //创建一个任务 Task<int> task = new Task<int>(() => { int sum = 0; Console.WriteLine("使用Task異步執行操作."); for (int i = 0; i <= 100; i++) { sum += i; } return sum; }); //启动任务,并安排到当前任务队列线程中执行任务(

  • C#连续任务Task.ContinueWith方法

    一.简介 通过任务,可以指定在任务完成之后,应开始运行之后另一个特定任务.ContinueWith是Task根据其自身状况,决定后续应该作何操作.也就是说,在运行完task后,会执行task.continuewith(XX)中的XX语句,但是是否执行.如何执行等需要看task的运行情况.例如:一个使用前一个任务的结果的新任务,如果前一个任务失败了,这个任务就应执行一些清理工作.任务处理程序都不带参数或者带一个对象参数,而任务的连续处理方法都有一个Task类型的参数. 二.案例 案例一: 代码:

  • C#并行编程之Task任务

    任务,基于线程池.其使我们对并行编程变得更简单,且不用关心底层是怎么实现的.System.Threading.Tasks.Task类是Task Programming Library(TPL)中最核心的一个类. 一.任务与线程 1:任务是架构在线程之上的,也就是说任务最终还是要抛给线程去执行. 2:任务跟线程不是一对一的关系,比如开10个任务并不是说会开10个线程,这一点任务有点类似线程池,但是任务相比线程池有很小的开销和精确的控制. 我们用VS里面的“并行任务”看一看,快捷键Ctrl+D,K,

  • C#并行编程之Task同步机制

    目录 一.隔离执行:不共享数据,让每个task都有一份自己的数据拷贝. 1.传统方式 2.ThreadLocal类 二.同步类型:通过调整task的执行,有序的执行task. 1.Lock锁 2.Interlocked 联锁 3.Mutex互斥体 三.申明性同步 四.并发集合 五.Barrier(屏障同步) 在并行计算中,不可避免的会碰到多个任务共享变量,实例,集合.虽然task自带了两个方法:task.ContinueWith()和Task.Factory.ContinueWhenAll()来

  • C#并行编程之PLINQ(并行LINQ)

    用于对内存中的数据做并行运算,也就是说其只支持 LINQ to Object 的并行运算 一.AsParallel(并行化) 就是在集合后加个AsParallel(). 例如: var numbers = Enumerable.Range(0, 100); var result = numbers.AsParallel().AsOrdered().Where(i => i % 2 == 0); foreach (var i in result) Console.WriteLine(i); 下面我

  • asyncio异步编程之Task对象详解

    目录 1.Task对象的作用 2.如何创建task对象 3.示例一(目前不推荐这种写法) 4.示例2 5.示例3(算是以上示例2的简化版) 总结 1.Task对象的作用 可以将多个任务添加到事件循环当中,达到多任务并发的效果 2.如何创建task对象 asyncio.create_task(协程对象) 注意:create_task只有在python3.7及以后的版本中才可以使用,就像asyncio.run()一样, 在3.7以前可以使用asyncio.ensure_future()方式创建tas

  • 深入学习C#网络编程之HTTP应用编程(下)

    第三篇来的好晚啊,上一篇说了如何向服务器推送信息,这一篇我们看看如何"快好准"的从服务器下拉信息. 网络上有很多大资源文件,比如供人下载的zip包,电影(你懂的),那么我们如何快速的进行下载,大家第一反应肯定就是多线程下载, 那么这些东西是如何做的呢?首先我们可以从"QQ的中转站里面拉一个rar下来". 然后用fiddler监视一下,我们会发现一个有趣的现象: 第一:7.62*1024*1024≈7990914  千真万确是此文件 第二:我明明是一个http链接,t

  • c++11多线程编程之std::async的介绍与实例

    本节讨论下在C++11中怎样使用std::async来执行异步task. C++11中引入了std::async 什么是std::async std::async()是一个接受回调(函数或函数对象)作为参数的函数模板,并有可能异步执行它们. template<class Fn, class... Args> future<typename result_of<Fn(Args...)>::type> async(launch policy, Fn&& fn

  • Android编程之Sdcard相关代码集锦

    本文实例讲述了Android编程之Sdcard相关代码.分享给大家供大家参考,具体如下: 1. 检测Sdcard是否可用: public static boolean sdCardIsAvailable() { String status = Environment.getExternalStorageState(); if (!status.equals(Environment.MEDIA_MOUNTED)) { return false; } return true; } 2. 获得程序在s

  • C# 网络编程之UDP

    一.概述 UDP和TCP是网络通讯常用的两个传输协议,C#一般可以通过Socket来实现UDP和TCP通讯,由于.NET框架通过UdpClient.TcpListener .TcpClient这几个类对Socket进行了封装,使其使用更加方便, 本文就通过这几个封装过的类讲解一下相关应用. 二.UDP基本应用 与TCP通信不同,UDP通信是不分服务端和客户端的,通信双方是对等的.为了描述方便,我们把通信双方称为发送方和接收方. 发送方: 首先创建一个UDP对象: string locateIP

  • c# 网络编程之tcp

    一.概述 UDP和TCP是网络通讯常用的两个传输协议,C#一般可以通过Socket来实现UDP和TCP通讯,由于.NET框架通过UdpClient.TcpListener .TcpClient这几个类对Socket进行了封装,使其使用更加方便, 本文就通过这几个封装过的类讲解一下相关应用. 二.基本应用:连接.发送.接收 服务端建立侦听并等待连接: TcpListener tcpListener = new TcpListener(IPAddress.Parse("127.0.0.1"

  • Python网络编程之ZeroMQ知识总结

    一.ZeroMQ概述 ZeroMQ(又名ØMQ,MQ,或zmq)像一个可嵌入的网络库,但其作用就像一个并发框架. ZeroMQ类似于标准Berkeley套接字,其提供了各种传输工具,如进程内.进程间.TCP和组播中进行原子消息传送的套接字 可以使用各种模式实现N对N的套接字连接,这些模式包括:发布-订阅.任务分配.请求-应答. ZeroMQ的速度足够快,因此可充当集群产品的结构. ZeroMQ的异步I/O模型提供了可扩展的多核应用程序,用异步消息来处理任务 ZeroMQ核心由C语言编写,支持C.

随机推荐