zoukankan      html  css  js  c++  java
  • 第三部分-并发设计模式33:Thread-Pre-Message设计模式

    1.Thread-Pre-Message 设计模式

    简单来说,就是为每个任务分配一个独立的线程,最简单的分工方法

    2.并发领域3个核心问题

    分工,同步,互斥

    同步,互斥源自微观,分工来自宏观

    Thread-Pre-Message其实就是一种分工模式

    3.映射现实世界

    教育小朋友搞不定,委托学校老师
    忙着写Bug,没时间买别墅,委托房产中介

    4.HttpServer

    自编HttpServer,主线程中接受请求,不能处理http请求,如果处理,就同时只能处理一个请求,太慢了。代办思路,创建子线程,委托子线程去处理http请求

    5.这种委托他人办理的方式,就是Thread-Pre-Message设计模式

    6.伪代码

    
    final ServerSocketChannel  = 
      ServerSocketChannel.open().bind(
        new InetSocketAddress(8080));
    //处理请求    
    try {
      while (true) {
        // 接收请求
        SocketChannel sc = ssc.accept();
        // 每个请求都创建一个线程
        new Thread(()->{
          try {
            // 读Socket
            ByteBuffer rb = ByteBuffer
              .allocateDirect(1024);
            sc.read(rb);
            //模拟处理请求
            Thread.sleep(2000);
            // 写Socket
            ByteBuffer wb = 
              (ByteBuffer)rb.flip();
            sc.write(wb);
            // 关闭Socket
            sc.close();
          }catch(Exception e){
            throw new UncheckedIOException(e);
          }
        }).start();
      }
    } finally {
      ssc.close();
    }   
    

    客户端发送什么,服务端返回什么
    但是上面伪代码不具有可行性,是因为java语言的问题,java中的线程是重量级的线程,创建成本高,而且创建线程比较耗时,而且占用内存也大。为每个请求创建一个新的线程也不适合高并发场景。

    7.线程池优化思路

    引入线程池会增加复杂度

    8.java中的线程

    java中的线程和操作系统是一一对应的,这种做法本质上是将java线程的调度权交给操作系统,操作系统在这方面比较成熟,好处是稳定,可靠。但是也继承了系统线程的缺点:创建成本高。
    所以java并发包提供了线程池工具类。这个思路在很长的时间内都是很稳妥的方案。

    9.轻量级线程-协程

    GO语言,lua,本质就是轻量级线程,创建成本低,基本与创建对象成本相似。创建速度于内存占用相比较操作系统的线程来说有一个数量级提升,基于协程实现Thread-Per-Message 模式完全没问题。一个请求一个线程。频繁创建协程,销毁协程序,几万个协程都可以接受。

    10.java的协程方案,Fiber(暂未商用,稳可靠性,稳定性还有待更多实践验证)

    伪代码

    
    final ServerSocketChannel ssc = 
      ServerSocketChannel.open().bind(
        new InetSocketAddress(8080));
    //处理请求
    try{
      while (true) {
        // 接收请求
        final SocketChannel sc = 
          ssc.accept();
        Fiber.schedule(()->{
          try {
            // 读Socket
            ByteBuffer rb = ByteBuffer
              .allocateDirect(1024);
            sc.read(rb);
            //模拟处理请求
            LockSupport.parkNanos(2000*1000000);
            // 写Socket
            ByteBuffer wb = 
              (ByteBuffer)rb.flip()
            sc.write(wb);
            // 关闭Socket
            sc.close();
          } catch(Exception e){
            throw new UncheckedIOException(e);
          }
        });
      }//while
    }finally{
      ssc.close();
    }
    

    ulimit -u 512,修改用户能创建的最大进程数(包括线程)设置为512
    使用ab压测,测试
    ab -r -c 20000 -n 200000
    -r 出错继续
    -c 并发2万
    -n 总共20万个请求

    压测结果:

    
    Concurrency Level:      20000
    Time taken for tests:   67.718 seconds
    Complete requests:      200000
    Failed requests:        0
    Write errors:           0
    Non-2xx responses:      200000
    Total transferred:      16400000 bytes
    HTML transferred:       0 bytes
    Requests per second:    2953.41 [#/sec] (mean)
    Time per request:       6771.844 [ms] (mean)
    Time per request:       0.339 [ms] (mean, across all concurrent requests)
    Transfer rate:          236.50 [Kbytes/sec] received
    
    Connection Times (ms)
                  min  mean[+/-sd] median   max
    Connect:        0  557 3541.6      1   63127
    Processing:  2000 2010  31.8   2003    2615
    Waiting:     1986 2008  30.9   2002    2615
    Total:       2000 2567 3543.9   2004   65293
    

    程序依然良好运行,同样使用new Thread()实现,512并发扛不住,就直接OOM了

    11.并发编程分工问题

    工具类中有

    Future,CompletableFuture,CompletionService,Fork/Join

    12.不需要并发读那么高的场景可以使用Thread-Pre-Message

    例如定时任务

    12.思考

    Thread-Per-Message 为每个人物创建一个线程,高并发中,很容易OOM,那么怎么能快速解决?

    (1)临时解决,修改jvm内存配置,增大jvm新生代大小
    (2)长期解决,引入NIO,使用netty
    (3)引入线程池控制,在请求端添加限流模块semaphore,自我保护
    (4)tomcat用的线程池的思路解决高并发问题
    (5)java中的线程是内核空间,协程是用户空间

    原创:做时间的朋友
  • 相关阅读:
    PHP post方式请求webservice接口以及解析返回的数据
    XYTipsWindow弹出层
    php使用rtrim时,可能会出现乱码
    带搜索的下拉框
    js实现自动给省市县地区自动赋值
    php 获取指定日期段内每一天的日期
    sqlserver数据库的备份和还原
    js判断哪个单选框应该被选中
    extjs3.1 解决列锁定,合计行不能滑动的问题
    考研数据结构-二叉树
  • 原文地址:https://www.cnblogs.com/PythonOrg/p/14872774.html
Copyright © 2011-2022 走看看