利用多线程实现流水线任务v0

文章介绍了如何使用多线程实现流水线,通过任务拆分提高效率。讨论了如何确保任务按照顺序执行,以及解决线程启动随机性带来的问题。通过Java代码示例展示了任务类和分任务线程的创建,最后提到了任务结束的判断与管理。
摘要由CSDN通过智能技术生成
  1. 利用多线程实现流水线的目的

  1. v0版流水线原理

  1. 具体代码演示

    • 利用流水线的目的

把一个大任务拆分成多个小任务

在完成第一个分任务之后便可以开始第二个大任务的第一个分任务,大大节约了时间

    • v0版流水线的原理

v0版流水线原理示意图

难点1:怎么保证流水线按照顺序执行?

由人工流水线试想如何让计算机达到像人工那样工作?

假设三个人甲乙丙一起完成造小车这项工作,甲完成了任务一之后会告诉乙“我完成了”,或者是乙通过观察,发现小车有了外壳,但没有发动机,意识到该自己做了,然后拿过半成品,进行分任务2.

这里的甲的话,或是乙的观察都是信号,让乙知道“It's my turn",这才有了turn(顺序)

同样的,我们需要给计算机信号,在任务一执行后有信号,在执行任务二前可以获得这个信号,这样就可以实现由甲到乙,由任务一到任务二的顺序

    boolean flag1;
    //java中布尔值默认为false
    boolean flag2;
    public void task1(){
        if(!flag1){
        num=10;
        System.out.println("执行了任务1");
        flag1=true;
     //既是给任务二的信号,也可以保证不会被重复执行任务一
    }}
    public void task2(){
        if(!flag2&&flag1){
        num*=num;
        System.out.println("执行了任务2");
        flag2=true;
    }}

难点1.1:计算机是个大傻子,即线程启动的随机性无法改变,怎么办呢?

上述操作的确可以保证整个大任务由123这样的顺序进行,但是如果先取任务的是分任务2,取的少,分任务1后取,取的多,那么之后的会有生产出的小车,但是前边一部分便无法产生出小车,极端情况下,分任务2先取,且每次多于分任务1,那么便永远无法生产小车因为需要保证是12,而不是21,这个顺序

以上描述的问题如下图所示

怎么解决嘞?

我们要是让分任务二这个线程再走一遍,是不是至少来说大任务一二三是可以进行第二分任务这一步了,因为大任务一二三的分任务1都已经完成。所以我们就可以通过让分任务1以外的其他分任务每隔一段时间再遍历一下任务组,说白了就是看看上一次遍历时候分任务1还没完成的任务,过了一段时间之后完成没,完成了就可以拿来进行分任务2了

while(true) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
             //每隔一段时间重新遍历
                for (int i = 0; i < al.size(); i++) {
                    Task task = al.get(i);
                      System.out.println("thread1取出第" + i + "个任务");

                    task.task1();
    • 具体代码演示

  1. 产生一个任务池子

public class ProduceTaskThread implements Runnable{
    //创建一个ArrayList用于存放生成的任务
    ArrayList<Task> al;

    public ProduceTaskThread(ArrayList<Task> al) {
        this.al = al;
    }

    @Override
    public void run() {
        for(int i=0;i<500;i++){
            Task task=new Task();
            al.add(task);
        }
        System.out.println("已经自动生成"+al.size()+"个任务");
    }
}
  1. 创建一个任务类

public class Task {
    int num;
    boolean flag1;
    //java中布尔值默认为false
    boolean flag2;
    boolean flag3;
    //设置标记

    public void task1(){
        if(!flag1){
        num=10;
        System.out.println("执行了任务1");
        flag1=true;
    }}
    public void task2(){
        if(!flag2&&flag1){
        num*=num;
        System.out.println("执行了任务2");
        flag2=true;
    }}
    public void task3(){
        if(!flag3&&flag2){
        num+=2;
        System.out.println("执行了任务3");
        flag3=true;}
    }
  1. 分任务线程

以一个分线程为例

class Task_Thread01 implements Runnable{
        ArrayList<Task> al;

        public Task_Thread01(ArrayList<Task> al) {
            this.al = al;
        }

        @Override
        public void run() {
            while(true) {
               //task1其实不需要
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
               
                int count=0;
                for (int i = 0; i < al.size(); i++) {
                    Task task = al.get(i);
                   //   System.out.println("thread1取出第" + i + "个任务");

                    task.task1();
                   
                    
                }}
        }
  1. 查看代码运行结果

线程全部跑完才能查看到最后的结果

怎么结束任务嘞?

以一个分任务为例

if (task.flag1) {
                        count++;
                    }
                }
                    if(count==500){
                        break;
                    }

Thread的join方法:

当前线程结束后才会执行后边的代码

分任务3结束后整个全部任务就真的结束了,所以用t3.join,之后,查看结果

 try {
                        t3.join();
         } catch (InterruptedException e) {
             throw new RuntimeException(e);
      }
        //查看结果
         //像数组、动态数组中所有数据的查看都是用到for遍历的
         //不是直接SOP
         for(int i=0;i<al.size();i++){
             Task task=al.get(i);
             System.out.println(task.num);
         }

本资源设置1个资源分,您可以下载作为捐献。 如果您有Git,还可以从http://www.goldenhawking.org:3000/goldenhawking/zoom.pipeline直接签出最新版本 (上一个版本“一种可伸缩的全异步C/S架构服务器实现”是有问题的,现在已经完成更改)。 服务由以下几个模块组成. 1、 网络传输模块。负责管理用于监听、传输的套接字,并控制数据流在不同线程中流动。数据收发由一定规模的线程池负责,实现方法完全得益于Qt的线程事件循环。被绑定到某个Qthread上的Qobject对象,其信号-槽事件循环由该线程负责。这样,便可方便的指定某个套接字对象使用的线程。同样,受惠于Qt的良好封装,直接支持Tcp套接字及SSL套接字,且在运行时可动态调整。(注:编译这个模块需要Qt的SSL支持,即在 configure 时加入 -openssl 选项) 2、 任务流水线模块。负责数据的处理。在计算密集型的应用中,数据处理负荷较重,需要和网络传输划分开。基于普通线程池的处理模式,也存在队列阻塞的问题——若干个客户端请求的耗时操作,阻塞了其他客户端的响应,哪怕其他客户端的请求很短时间就能处理完毕,也必须排队等待。采用流水线线程池避免了这个问题。每个客户端把需要做的操作进行粒度化,在一个环形的队列中,线程池对单个客户端,每次仅处理一个粒度单位的任务。单个粒度单位完成后,该客户端的剩余任务便被重新插入到队列尾部。这个机制保证了客户端的整体延迟较小。 3、 服务集群管理模块。该模块使用了网络传输模块、任务流水线模块的功能,实现了跨进程的服务器ßà服务器链路。在高速局域网中,连接是快速、稳定的。因此,该模块被设计成一种星型无中心网络。任意新增服务器节点选择现有服务器集群中的任意一个节点,接入后,通过广播自动与其他服务器节点建立点对点连接。本模块只是提供一个服务器到服务器的通信隧道,不负责具体通信内容的解译。对传输内容的控制,由具体应用决定。 4、 数据库管理模块。该模块基于Qt的插件式数据库封装QtSql。数据库被作为资源管理,支持在多线程的条件下,使用数据库资源。 5、 框架界面。尽管常见的服务运行时表现为一个后台进程,但为了更好的演示服务器的功能,避免繁琐的配置,还是需要一个图形界面来显示状态、设置参数。本范例中,界面负责轮训服务器的各个状态,并设置参数。设置好的参数被存储在一个ini文件中,并在服务开启时加载。 6、应用专有部分模块。上述1-4共四个主要模块均是通用的。他们互相之间没有形成联系,仅仅是作为一种资源存在于程序的运行时(Runtime)之中。应用专有部分模块根据具体任务需求,灵活的使用上述资源,以实现功能。在范例代码中,实现了一种点对点的转发机制。演示者虚拟出一些工业设备,以及一些操作员使用的客户端软件。设备与客户端软件在成功认证并登录后,需要交换数据。改变这个模块的代码,即可实现自己的功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值