为什么要学习多线程?

  • 2010年1月21日是10年某市公务员考试的报名截止日。因从下午2点开始,用于报名的北京市人事考试网瘫痪,原定于昨天下午5点截止的报名时间延迟至今天上午11点。
  • 2011年3月11日下午5时(北京时间12日早9点),苹果发布新一代的平板电脑产品iPad 2,配备了A5.1Ghz双核处理器,这寓意着平板电脑和笔记本一同进入"多核时代"。
  • 同年6月18日,国内著名B2C---京东在周年庆典之际举行了"隆重"的大规模的促销活动,抢购随之而来,订单挤爆京东 限时达临时取消。 昨天有消费者反映,由于点击量过大,18日早上京东商城网站一度瘫痪。一位消费者说:“18日凌晨1点开始就登不上京东商城。”刘强东也表示:由于流量多次超过4个G,服务器运行缓慢。 昨天,京东商城官网发布公告称,“‘618’活动异常火爆且用户下单速度空前,致使部分用户已购订单显示出现延迟,用户在一段时间内无法在‘我的京东’中查询到自己的订单。目前已购订单显示延迟的问题已得到有效解决,对此给您带来的不便,我们深表歉意。”
  • 2015年05月05日登录风信子网上商城发现,首页除了广告和相关消息外,只有“注册账号获取更多优惠”这唯一一个按钮,没有商品展示,没有产品搜索,不能网上下单,甚至连进入商城的按钮也没有。风信子南沙跨境商品直购体验中心相关负责人表示,这主要是因为预约的人数太多,截至五一,预约人数已超过十万,太多人频繁登陆,导致网店服务器瘫痪,目前技术人员还在努力维修中。该负责人介绍,体验中心的网站目前正在调试,“网站目前的作用主要是给市民预约和提前注册,通过网络注册的市民不用在现场验证身份证等信息,可以提高购买效率。”

下面通过一些实例来认识一下多线程和让大家知道为什么要学习多线程。

v写在前面

老板只有两种,好的和坏的。好的老板只跟你谈钱,坏的老板只跟你谈理想。

v模拟场景

假设后台有个monitor时事的在监测订单,且可以发现订单然后处理订单,每次(1次/S)可以处理1千个订单,需要向仓库系统发出指令,让他们负责配送发货。那么我们来写一个EmulationSystem(模拟系统)

JobHelper因为我们只是为了模拟一个环境,所以它是这样的。

//------------------------------------------------------------------------------
// <copyright file="JobHelper.cs" company="CNBlogs Corporation" owner="请叫我头头哥">
// Copyright (C) 2015-2016 All Rights Reserved
// 原博文地址: http://www.cnblogs.com/toutou/
// </copyright>
//------------------------------------------------------------------------------
namespace CNBlogs.Common.Shared
{
using System.Threading;
/// <summary>
/// Job helper
/// </summary>
public class JobHelper
{
/// <summary>
/// Get job total count
/// </summary>
/// <returns></returns>
public int GetJobCount()
{
// 我们的侧重点是多线程,所以我们就模拟每次有1千个订单,而模拟,所以我们不关心其他的。只要订单数量。
return ;
}
/// <summary>
/// Submit job
/// </summary>
/// <param name="jobId">For job id</param>
/// <returns>Submit job status</returns>
public bool SubmitJob(int jobId)
{
// 假设针对每个订单向后台发送任务需要1秒,而且每个订单都能成功发送
Thread.Sleep();
return true;
}
}
}

背景我们也交待完了,现在需要来得到这些订单信息以后,向仓库submit这些订单。

v实战演习

根据这种背景,我们可以有很多处理的办法。

  • 传统办法:

    (开启无脑模式:未使用多线程)

    代码正文:

    //------------------------------------------------------------------------------
    // <copyright file="Runner.cs" company="CNBlogs Corporation" owner="请叫我头头哥">
    // Copyright (C) 2015-2016 All Rights Reserved
    // 原博文地址: http://www.cnblogs.com/toutou/
    // </copyright>
    //------------------------------------------------------------------------------
    namespace CNBlogs.EmulationSystem
    {
    using System;
    using System.Threading;
    using CNBlogs.Common.Shared;
    class Runner
    {
    /// <summary>
    /// Job helper
    /// </summary>
    private static JobHelper jobHelper = new JobHelper();
    /// <summary>
    /// Runner lock
    /// </summary>
    private static Mutex mutex;
    static void Main(string[] args)
    {
    // 记录开始处理的时间
    DateTime paddingTime = DateTime.Now.ToLocalTime();
    int orderCount = jobHelper.GetJobCount();
    // 用一个指示调用线程是否应拥有互斥体的初始所属权的布尔值来初始化 Mutex 类的新实例。
    // 当前进程只能启动一次
    mutex = new Mutex(false, "CNBlogs.EmulationSystem");
    if (!mutex.WaitOne(, false))
    {
    Console.Out.WriteLine("Monitor already running...");
    return;
    }
    for (int i = ; i < orderCount; i++)
    {
    // 假设i就是job id
    jobHelper.SubmitJob(i);
    }
    // 记录处理完成的时间
    DateTime completeTime = DateTime.Now.ToLocalTime();
    var minutes = (completeTime - paddingTime).TotalSeconds;
    Console.WriteLine(string.Format("处理{0}个订单,花费时间{1}秒", orderCount, minutes));
    }
    }
    }

    代码效果:

    PS:现在的这些个电商,动不动来个什么周年庆店庆什么双11双12的一顿突突,搞得咱这些老百姓就全部蜂拥而上,显然如果用传统的方法虽然不会出错,但是老板肯定会找你喝茶。在多核时代用这种方法也只能铁不成钢了。所以这个方法是绝对不可取的。

  • Task方法:

    如果有对Task不是很熟悉的园友可以在这里解开心谜。

    代码正文:

    //------------------------------------------------------------------------------
    // <copyright file="Runner.cs" company="CNBlogs Corporation" owner="请叫我头头哥">
    // Copyright (C) 2015-2016 All Rights Reserved
    // 原博文地址: http://www.cnblogs.com/toutou/
    // </copyright>
    //------------------------------------------------------------------------------
    namespace CNBlogs.EmulationSystem
    {
    using System;
    using System.Collections.Generic;
    using System.Threading;
    using System.Threading.Tasks;
    using CNBlogs.Common.Shared;
    class Runner
    {
    /// <summary>
    /// Job helper
    /// </summary>
    private static JobHelper jobHelper = new JobHelper();
    /// <summary>
    /// Runner lock
    /// </summary>
    private static Mutex mutex;
    static void Main(string[] args)
    {
    // 记录开始处理的时间
    DateTime paddingTime = DateTime.Now.ToLocalTime();
    int orderCount = jobHelper.GetJobCount();
    // 用一个指示调用线程是否应拥有互斥体的初始所属权的布尔值来初始化 Mutex 类的新实例。
    // 当前进程只能启动一次
    mutex = new Mutex(false, "CNBlogs.EmulationSystem");
    if (!mutex.WaitOne(, false))
    {
    Console.Out.WriteLine("Monitor already running...");
    return;
    }
    var taskList = new List<Task>();
    for (int i = ; i < orderCount; i++)
    {
    int temp=i;
    taskList.Add(Task.Factory.StartNew(() =>
    {
    // 假设i就是job id
    jobHelper.SubmitJob(temp);
    }));
    }
    // 等待所有task执行完毕
    Task.WaitAll(taskList.ToArray());
    // 记录处理完成的时间
    DateTime completeTime = DateTime.Now.ToLocalTime();
    var minutes = (completeTime - paddingTime).TotalSeconds;
    Console.WriteLine(string.Format("Complete: {0},cost {1} s", orderCount, minutes));
    }
    }
    }

    代码效果:

    相信分别从有TASK和没有TASK的这两次demo中,可以清楚的发现多线程处理这些频繁交互能力的魅力。你会爱上这个方法。确实提高的效率。但是问题也随之而来,一个进程多线程的总数和大小是有要求的(这个取决于服务器的配置),不是任由我们肆意的开采的。如果订单太多,我们不控制task那是会拉仇恨的。task需要控制。

  • Semaphore:

    如果有对Semaphore不是很熟悉的园友可以在这里解开心谜。

    代码正文:

    //------------------------------------------------------------------------------
    // <copyright file="Runner.cs" company="CNBlogs Corporation" owner="请叫我头头哥">
    // Copyright (C) 2015-2016 All Rights Reserved
    // 原博文地址: http://www.cnblogs.com/toutou/
    // </copyright>
    //------------------------------------------------------------------------------
    namespace CNBlogs.EmulationSystem
    {
    using System;
    using System.Collections.Generic;
    using System.Threading;
    using System.Threading.Tasks;
    using CNBlogs.Common.Shared;
    class Runner
    {
    /// <summary>
    /// Job helper
    /// </summary>
    private static JobHelper jobHelper = new JobHelper();
    /// <summary>
    /// The locker used to lock the semaphore and thread.
    /// </summary>
    private static object lockerObj = new object();
    /// <summary>
    /// The semaphore limit the thread number of get latest test info
    /// </summary>
    private static Semaphore semaphoreLimit;
    /// <summary>
    /// Runner lock
    /// </summary>
    private static Mutex mutex;
    static void Main(string[] args)
    {
    // 记录开始处理的时间
    DateTime paddingTime = DateTime.Now.ToLocalTime();
    int orderCount = jobHelper.GetJobCount();
    // 用一个指示调用线程是否应拥有互斥体的初始所属权的布尔值来初始化 Mutex 类的新实例。
    // 当前进程只能启动一次
    mutex = new Mutex(false, "CNBlogs.EmulationSystem");
    if (!mutex.WaitOne(, false))
    {
    Console.Out.WriteLine("Monitor already running...");
    return;
    }
    // 假设我们的服务器一个进程只能接受的大小=当前线程大小*500 ps:500是设置信号量的最大值
    int maxProcNumber = ;
    using (semaphoreLimit = new Semaphore(, maxProcNumber))
    {
    // 以指定的次数退出信号量并返回前一个计数。
    semaphoreLimit.Release(maxProcNumber);
    var taskList = new List<Task>();
    for (int i = ; i < orderCount; i++)
    {
    int temp=i;
    // 如果SubmitJob有IO或者其他容易因为冲突而引起异常的话,这里需要加上lock
    //lock (lockerObj)
    //{
    semaphoreLimit.WaitOne();
    taskList.Add(Task.Factory.StartNew(() =>
    {
    // 假设i就是job id
    jobHelper.SubmitJob(temp);
    // 退出信号量并返回前一个计数。
    semaphoreLimit.Release();
    }));
    //}
    }
    // 等待所有task执行完毕
    Task.WaitAll(taskList.ToArray());
    }
    // 记录处理完成的时间
    DateTime completeTime = DateTime.Now.ToLocalTime();
    var minutes = (completeTime - paddingTime).TotalSeconds;
    Console.WriteLine(string.Format("Complete: {0},cost {1} s", orderCount, minutes));
    }
    }
    }

    代码效果:

v博客总结

多线程路还很长...

作  者:请叫我头头哥

出  处:http://www.cnblogs.com/toutou/

关于作者:专注于基础平台的项目开发。如有问题或建议,请多多赐教!

版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信

声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是作者坚持原创和持续写作的最大动力!

C# 多线程,论多核时代爱恨情仇的更多相关文章

  1. String、StringBuilder、StringBuffer的爱恨情仇

    第三阶段 JAVA常见对象的学习 StringBuffer和StringBuilder类 (一) StringBuffer类的概述 (1) 基本概述 下文以StringBuffer为例 前面我们用字符 ...

  2. Menu与ActionBar的爱恨情仇

    最近在开发一款音乐播放器,在开发过程中遇到了一点小麻烦,通过android API搞清楚了Menu与ActionBar的爱恨情仇,写了个小Demo祭奠一下那些年我们陷进去的坑,有不对的地方请大神们批评 ...

  3. web移动端fixed布局和input等表单的爱恨情仇 - 终极BUG,完美解决

    [问题]移动端开发,ios下当fixed属性和输入框input(这里不限于input,只要可以调用移动端输入法的都包括,如:textarea.HTML5中contenteditable等),同时存在的 ...

  4. 注解:大话AOP与Android的爱恨情仇

    转载:大话AOP与Android的爱恨情仇 1. AOP与OOP的区别 平时我接触多的就是OOP(Object Oriented Programming面向对象).AOP(Aspect Oriente ...

  5. 除了love和hate,还能怎么表达那些年的“爱恨情仇”?

    实用英语 帮你全面提高英语水平 关注 童鞋们每次刷美剧的时候,相信都会被CP感满满的男女主角虐得体无完肤吧. 可是,一到我们自己表达爱意或者恨意的时候,却苦于词穷,只会用love, like, hat ...

  6. 对json的爱恨情仇

    本文回想了对json的爱恨情仇. C++有风险,使用需慎重. 本文相关代码在:http://download.csdn.net/detail/baihacker/7862785 当中的測试数据不在里面 ...

  7. [转帖]探秘华为(一):华为和H3C(华三)的爱恨情仇史!

    探秘华为(一):华为和H3C(华三)的爱恨情仇史! https://baijiahao.baidu.com/s?id=1620703498823290828&wfr=spider&fo ...

  8. Tidyverse|数据列的分分合合,爱恨情仇

    Tidyverse|数据列的分分合合,爱恨情仇 本文首发于“生信补给站”Tidyverse|数据列的分分合合,一分多,多合一 TCGA数据挖掘可做很多分析,前期数据“清洗”费时费力但很需要. 比如基因 ...

  9. pytorch和tensorflow的爱恨情仇之基本数据类型

    自己一直以来都是使用的pytorch,最近打算好好的看下tensorflow,新开一个系列:pytorch和tensorflow的爱恨情仇(相爱相杀...) 无论学习什么框架或者是什么编程语言,最基础 ...

随机推荐

  1. vim退出后终端保留 退出前的内容

    export TERM=linux 或者 具体选项 可以看看secrecrt的选项

  2. volcanol_Linux_ 问题汇总系列_4_Thinkpad_E40_0578MDC_在Fedora 13 Linux(FC13)中如何安装无线网卡驱动

    今天晚上,我突然想在自己到笔记本上安装linux系统,因为我自己第一次接触到的linux是红帽支持到Fedora Core 4,所以一直最中意的linux 发行版本是FC系列,同时由于FC 15以后到 ...

  3. Oracle Database 11g For Windows7 旗舰版的安装

    系统环境:win7 32位系统 安装步骤: 1,Oracle(甲骨文)官网下载适合自己的数据库安装包,下载地址http://www.oracle.com/technetwork/cn/indexes/ ...

  4. 历史疑团之EJB

    在学习Sping框架的过程中,看到过很多次关于EJB的批判.使用了SpringMVC但是并没有真性情般体会到它的优点,所以有必要对传统的Java Bean和EJB来做一些了解,无奈百度搜了很多知识,还 ...

  5. 设置placeholder字体颜色

    /*设置placeholder字体颜色*/::-webkit-input-placeholder{ color: #FFF;}:-ms-input-placeholder{ color: #FFF;} ...

  6. MySQL配置文件mysql.ini参数详解、MySQL性能优化

    my.ini(Linux系统下是my.cnf),当mysql服务器启动时它会读取这个文件,设置相关的运行环境参数. my.ini分为两块:Client Section和Server Section.  ...

  7. jstl标签

    为什么提出jstl标签? Jsp中包含html标签+java片段+jsp片段使得jsp页面比较乱.提出:能不能把<% %>java片段用标签替换 jsp页面更简洁 <!-- 引入js ...

  8. iOS 代理反向传值

    在上篇博客 iOS代理协议 中,侧重解析了委托代理协议的概念等,本文将侧重于它们在开发中的应用. 假如我们有一个需求如下:界面A上面有一个button.一个label.从界面A跳转到界面B,在界面B的 ...

  9. Ioc Autofac心得

    对于这个容器注入,个人也不是很熟悉,很多还不懂,只会基本的操作,几天把它记录下来,说不定以后帮助就大了呢,这方面跟安卓差距还是挺大的 下面记录下应用的流程 步骤: 1.添加应用 2.重写工厂(这里讲的 ...

  10. Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论

    Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论 创建用户自定义的类加载器 要创建用户自定义的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的f ...