精华内容
下载资源
问答
  • 任务队列
    千次阅读
    2021-02-12 10:06:47

    Java任务队列在不断的学习中需要我们掌握很多相关的技术信息。

    首先,下面我们就看看如何应用TaskQueue的具体问题。

    Java任务队列需要我们详细的学习,

    当然我们在不断的使用中还需要注意相关信息的学习。

    下面我们就先来看看TaskQueue(任务队列)的具体应用。

    下面我们就详细的学习下。

    在同一时刻,可能有很多任务需要执行,

    而程序在同一时刻只能执行一定数量的任务,

    当需要执行的任务数超过了程序所能承受的任务数时怎么办呢?

    这就有了先执行哪些任务,后执行哪些任务的规则。

    TaskQueue类就定义了这些规则中的一种,它采用的是FIFO(先进先出,英文名是First In

    First Out)的方式,也就是按照任务到达的先后顺序执行。TaskQueue类的定义。

    Java任务队列代码如下:

    import java.util.Iterator;

    import java.util.LinkedList;

    import java.util.List;

    public class TaskQueue {

    private List queue = new LinkedList(); // 添加一项任务

    public synchronized void addTask(Task task) {

    if (task != null) {

    queue.add(task);

    }

    } // 完成任务后将它从任务队列中删除

    public synchronized void finishTask(Task task) {

    if (task != null) {

    task.setState(Task.State.FINISHED);

    queue.remove(task);

    }

    } // 取得一项待执行任务

    public synchronized Task getTask() {

    Iterator it = queue.iterator();

    Task task;

    while (it.hasNext()) {

    task = it.next(); // 寻找一个新建的任务

    if (Task.State.NEW.equals(task.getState())) { // 把任务状态置为运行中

    task.setState(Task.State.RUNNING);

    return task;

    }

    }

    return null;

    }

    }

    import java.util.Iterator;

    import java.util.LinkedList;

    import java.util.List;

    public class TaskQueue {

    private List queue = new LinkedList(); // 添加一项任务

    public synchronized void addTask(Task task) {

    if (task != null) {

    queue.add(task);

    }

    } // 完成任务后将它从任务队列中删除

    public synchronized void finishTask(Task task) {

    if (task != null) {

    task.setState(Task.State.FINISHED);

    queue.remove(task);

    }

    } // 取得一项待执行任务

    public synchronized Task getTask() {

    Iterator it = queue.iterator();

    Task task;

    while (it.hasNext()) {

    task = it.next(); // 寻找一个新建的任务

    if (Task.State.NEW.equals(task.getState())) { // 把任务状态置为运行中

    task.setState(Task.State.RUNNING);

    return task;

    }

    }

    return null;

    }

    }

    更多相关内容
  • 使用redis做任务队列分发子任务,用于分布式拆分子任务提高系统运行效率
  • ThreadPool 线程池+任务队列
  • 摸索出来这个的原因 是由于需要有序的播放多个声音的原因 需要以任务队列的形式 完成一个任务继续下一个 后面发现任务队列本身因为是后台的 发现跑同一个接口但次数很多的时候很好用
  • Android中的线程池与任务队列
  • 深入学习JS:任务队列和事件循环

    千次阅读 2022-03-23 17:14:01
    目录一、问题二、js中的任务队列三、解决 一、问题 二、js中的任务队列 我们知道js是单线程的: JS作为浏览器的脚本语言,主要的用途就是与用户互动,操作dom,这也是根本原因决定JS是单线程的原因。 设想一个线程...

    一、问题

    在学习任务队列和事件循环之前,来看一个for循环中调用setTimeout的输出问题。

    for(var i = 0; i < 10; i++){
        setTimeout(()=>{
            console.log(i);
        }, 1000)
    }
    /**
     * 实际输出:
     * (大概1s后),输出:
     * 10
     * 10
     * 10
     * 10
     * 10
     * 10
     * 10
     * 10
     * 10
     * 10
     */
    

    在这里插入图片描述

    我们期望的结果应该是每隔1s,依次输出1、2、3……9,然而实际输出确实1s后同时输出10个10!这是为什么呢?那么接下来学习了JavaScript中的任务队列和事件循环后,答案就会揭晓。

    二、任务队列与事件循环

    我们来看看js的事件执行机制:
    在这里插入图片描述

    我们知道js是单线程的:

    JS作为浏览器的脚本语言,主要的用途就是与用户互动,操作dom,这也是根本原因决定JS是单线程的原因。 设想一个线程在DOM上添加元素,而另一个线程删除了这个节点,那这个时候应该听谁的?

    2.1 同步任务与异步任务

    在JavaScript中,所有任务可以分为两种,一种是同步任务,一种是异步任务。

    • 同步任务:同步任务是在主线程(这个线程用来解释和执行 JavaScript 代码)上排队执行的任务。
    • 异步任务:不进入主线程、而进入任务队列的任务。只有当主线程上的所有同步任务执行完毕之后,主线程才会读取任务队列,将任务放到执行栈,开始执行任务。(例如:ajax请求、io操作、setTimeout等事件调用的回调函数)

    2.2 任务队列

    当遇到计时器(setTimeout)、DOM事件监听或者是网络请求的任务时,JS引擎会将它们直接交给 webapi,也就是浏览器提供的相应线程(如定时器线程为setTimeout计时、异步http请求线程处理网络请求)去处理,而JS引擎线程继续后面的其他任务,这样便实现了 异步非阻塞。

    定时器触发线程也只是为 setTimeout(…, 1000) 定时而已,时间一到(1s过后),还会把它对应的回调函数(callback)交给 任务队列 去维护,JS引擎线程会在适当的时候去任务队列取出任务并执行。

    所以我们可以说:任务队列存储了来自webapi的回调函数,这些函数等待被系统调用到执行栈(也就是主线程)上去运行。

    2.3 事件循环(event loop)

    js引擎遇到一个异步事件后并不会一直等待其返回结果,而是会将这个事件挂起(交给webapi处理),继续执行执行栈中的其他任务。当一个异步事件返回结果后(例如延时时间到了、ajax得到结果了等),js会将这个事件加入与当前执行栈不同的另一个队列,我们称之为任务(事件)队列。被放入任务队列不会立刻执行其回调,而是等待当前执行栈中的所有任务都执行完毕, 主线程处于闲置状态时,主线程会去查找事件队列是否有任务。如果有,那么主线程会从中取出排在第一位的事件,并把这个事件对应的回调放入执行栈中,然后执行其中的同步代码…,如此反复,这样就形成了一个无限的循环。这就是这个过程被称为“事件循环(Event Loop)”的原因。

    来简述一下setTimeout中的输出事件的执行:

    1. 首先在主线程上,运行到setTimeout函数时,把它交给webapi处理。
    2. wepapi对setTimeout函数进行处理,即1s后,setTimeout的延时任务完成,应该调用回调函数(输出)了。但并不会立即将回调函数送入主线程,不然就会乱套了,得排队。
    3. 1s后,webapi将setTimeout(consloe.log(i))交给任务队列,此时setTimeout函数在任务队列中排队。
    4. 主线程中所有任务完成后,此时将任务队列的排第一事件(setTimeout)取出来放到执行栈中去执行,运行其中的同步函数(回调函数)。
    5. 当输出运行完以后,如果任务队列不为空,又将排第一的事件取出来执行,如此往复,就形成了上述的事件循环(event loop)

    三、解决

    了解了任务队列和事件循环等,来解决一下博客开头提出的问题吧。
    首先分析一下为什么:

    • 同时输出问题:我们知道for循环的运行时间是可以忽略不记的,所以几乎同时10个setTimeout函数被交给了webapi处理,那么这10个setTimeout的延时也可以认为是同1s中,所以他们10个1s后几乎同时从webapi进入任务队列等待被执行,但是还是要排队哦,所以我们得让每个setTimeout得延时不一样。
    • 都输出10问题:for循环结束时,i已经变成10了,而延时函数得回调函数执行一定是在for循环之后的,因为for循环是同步任务。所以当延时函数的回调函数被执行时,输出的i是已经变成10了。

    3.1 解决同时输出

     for(var i = 0; i < 10; i++){
        setTimeout(()=>{
            console.log(i);
        }, 1000*i)
    }
    /**
     * 实际输出:
     * 输出:
     * 10(立刻输出)
     * 10(1s)
     * 10(2s)
     * 10(3s)
     * 10(4s)
     * 10(5s)
     * 10(6s)
     * 10(7s)
     * 10(8s)
     * 10(9s)
     */
    

    3.2 解决全输出10问题

    使用let定义i,此时i的作用域便不是全局了。

     for(let i = 0; i < 10; i++){
        setTimeout(()=>{
            console.log(i);
        }, 1000*i)
    }
    /**
     * 实际输出:
     * 输出:
     * 0(立刻输出)
     * 1(1s)
     * 2(2s)
     * 3(3s)
     * 4(4s)
     * 5(5s)
     * 6(6s)
     * 7(7s)
     * 8(8s)
     * 9(9s)
     */
    
    展开全文
  • 总结事件轮询机制,以及宏任务队列与微任务队列

    千次阅读 多人点赞 2019-04-15 09:45:06
    1. 事件轮询(Event Loop) js实现异步的具体解决方案 ...EXP4:微任务队列中创建的宏任务 总结 这篇博文仅为个人理解,文章内提供一些更加权威的参考,如有片面及错误,欢迎指正 1. 事件轮询...

    这篇博文仅为个人理解,文章内提供一些更加权威的参考,如有片面及错误,欢迎指正

    1. 事件轮询(Event Loop)

    什么是 Event Loop? - 阮一峰

    事件轮询(Event Loop) - 《你不懂JS:异步与性能》

    【推荐】详解JavaScript中的Event Loop(事件循环)机制

    Javascript的宿主环境中共通的一个“线程”(一个“不那么微妙”的异步玩笑,不管怎样)是,他们都有一种机制:在每次调用JS引擎时,可以随着时间的推移执行你的程序的多个代码块儿,这称为“事件轮询(Event Loop)”。

    换句话说,JS引擎对 时间 没有天生的感觉,反而是一个任意JS代码段的按需执行环境。是它周围的环境在不停地安排“事件”(JS代码的执行)。

    js实现异步的具体解决方案

    • 同步代码直接执行
    • 异步函数到了指定时间再放到异步队列
    • 同步执行完毕,异步队列轮询执行。

    什么叫轮询?

    精简版:当第一个异步函数执行完之后,再到异步队列监视。一直不断循环往复,所以叫事件轮询。

    详细版:js引擎遇到一个异步事件后并不会一直等待其返回结果,而是会将这个事件挂起,继续执行执行栈中的其他任务。当一个异步事件返回结果后,js会将这个事件加入与当前执行栈不同的另一个队列,我们称之为事件队列。被放入事件队列不会立刻执行其回调,而是等待当前执行栈中的所有任务都执行完毕, 主线程处于闲置状态时,主线程会去查找事件队列是否有任务。如果有,那么主线程会从中取出排在第一位的事件,并把这个事件对应的回调放入执行栈中,然后执行其中的同步代码…,如此反复,这样就形成了一个无限的循环。这就是这个过程被称为“事件循环(Event Loop)”的原因。

    事实上,事件轮询与宏任务和微任务密切相关。

    2. 宏任务和微任务

    概念

    微任务、宏任务与Event-Loop

    在一个事件循环中,异步事件返回结果后会被放到一个任务队列中。然而,根据这个异步事件的类型,这个事件实际上会被对应的宏任务队列或者微任务队列中去。并且在当前执行栈为空的时候,主线程会 查看微任务队列是否有事件存在。如果不存在,那么再去宏任务队列中取出一个事件并把对应的回到加入当前执行栈;如果存在,则会依次执行队列中事件对应的回调,直到微任务队列为空,然后去宏任务队列中取出最前面的一个事件,把对应的回调加入当前执行栈…如此反复,进入循环。

    我们只需记住当当前执行栈执行完毕时会立刻先处理所有微任务队列中的事件,然后再去宏任务队列中取出一个事件。同一次事件循环中,微任务永远在宏任务之前执行。

    在当前的微任务没有执行完成时,是不会执行下一个宏任务的。
    所以就有了那个经常在面试题、各种博客中的代码片段:

    setTimeout(_ => console.log(4))
    
    new Promise(resolve => {
      resolve()
      console.log(1)
    }).then(_ => {
      console.log(3)
    })
    
    console.log(2)
    

    setTimeout就是作为宏任务来存在的,而Promise.then则是具有代表性的微任务,上述代码的执行顺序就是按照序号来输出的。
    所有会进入的异步都是指的事件回调中的那部分代码
    也就是说new Promise在实例化的过程中所执行的代码都是同步进行的,而then中注册的回调才是异步执行的。
    在同步代码执行完成后才回去检查是否有异步任务完成,并执行对应的回调,而微任务又会在宏任务之前执行。
    所以就得到了上述的输出结论1、2、3、4。

    +部分表示同步执行的代码

    +setTimeout(_ => {
    -  console.log(4)
    +})
    
    +new Promise(resolve => {
    +  resolve()
    +  console.log(1)
    +}).then(_ => {
    -  console.log(3)
    +})
    
    +console.log(2)
    

    本来setTimeout已经先设置了定时器(相当于取号),然后在当前进程中又添加了一些Promise的处理(临时添加业务)。

    所以进阶的,即便我们继续在Promise中实例化Promise,其输出依然会早于setTimeout的宏任务:如EXP2

    宏任务

    分类:

    #浏览器Node
    I/O
    setTimeout
    setInterval
    setImmediate
    requestAnimationFrame

    特性:

    1. 宏任务所处的队列就是宏任务队列

    2. 第一个宏任务队列中只有一个任务:执行主线程上的JS代码;如果遇到上方表格中的异步任务,会创建出一个新的宏任务队列,存放这些异步函数执行完成后的回调函数。

    3. 宏任务队列可以有多个

    4. 宏任务中可以创建微任务,且如果该微任务立即被加入执行栈的话,会打断当前宏任务的执行。(EXP3)

    5. 当一个宏任务队列中的任务全部执行完后,会查看是否有微任务队列,如果有就会优先执行微任务队列中的所有任务,如果没有就查看是否有宏任务队列

    微任务

    分类:

    #浏览器Node
    process.nextTick
    MutationObserver
    Promise.then catch finally

    特性:

    1. 微任务所处的队列就是微任务队列

    2. 在上一个宏任务队列执行完毕后,如果有微任务队列就会执行微任务队列中的所有任务

    3. new promise((resolve)=>{ 这里的函数在当前队列直接执行 }).then( 这里的函数放在微任务队列中执行 )

    4. 微任务队列上创建的微任务,仍会阻碍后方将要执行的宏任务队列 (EXP2)

    5. 由微任务创建的宏任务,会被丢在异步宏任务队列中执行 (EXP4)

    例题

    EXP1: 在主线程上添加宏任务与微任务

    执行顺序:主线程 => 主线程上创建的微任务 => 主线程上创建的宏任务

    console.log('-------start--------');
    
    setTimeout(() => {
      console.log('setTimeout');  // 将回调代码放入另一个宏任务队列
    }, 0);
    
    new Promise((resolve, reject) => {
      for (let i = 0; i < 5; i++) {
        console.log(i);
      }
      resolve()
    }).then(()=>{
      console.log('Promise实例成功回调执行'); // 将回调代码放入微任务队列
    })
    
    console.log('-------end--------');
    

    结果:

    -------start--------
    0
    1
    2
    3
    4
    -------end--------
    Promise实例成功回调执行
    setTimeout
    

    由EXP1,我们可以看出,当JS执行完主线程上的代码,会去检查在主线程上创建的微任务队列,执行完微任务队列之后才会执行宏任务队列上的代码

    EXP2: 在微任务中创建微任务

    执行顺序:主线程 => 主线程上创建的微任务1 => 微任务1上创建的微任务2 => 主线程上创建的宏任务

    setTimeout(_ => console.log(4))
    
    new Promise(resolve => {
      resolve()
      console.log(1)
    }).then(_ => {
      console.log(3)
      Promise.resolve().then(_ => {
        console.log('before timeout')
      }).then(_ => {
        Promise.resolve().then(_ => {
          console.log('also before timeout')
        })
      })
    })
    
    console.log(2)
    

    结果:

    1
    2
    3
    before timeout
    also before timeout
    4
    

    由EXP1,我们可以看出,在微任务队列执行时创建的微任务,还是会排在主线程上创建出的宏任务之前执行

    EXP3: 宏任务中创建微任务

    宏任务队列中创建的微任务,会打断当前宏任务队列的执行。

    执行顺序:主线程(宏任务队列 1)=> 宏任务队列 2.1 => 微任务队列 1(打断宏任务队列 2)=>宏任务队列 2.2 => 宏任务队列 3

    // 宏任务队列 1
    setTimeout(() => {
      // 宏任务队列 2.1
      console.log('timer_1');
      setTimeout(() => {
        // 宏任务队列 3
        console.log('timer_3')
      }, 0)
      new Promise(resolve => {
        resolve()
        console.log('new promise')
      }).then(() => {
        // 微任务队列 1
        console.log('promise then')
      })
    }, 0)
    
    setTimeout(() => {
      // 宏任务队列 2.2
      console.log('timer_2')
    }, 0)
    
    console.log('========== Sync queue ==========')
    

    结果:

    ========== Sync queue ==========
    timer_1
    new promise
    promise then
    timer_2
    timer_3
    

    EXP4:微任务队列中创建的宏任务

    执行顺序:主线程 => 主线程上创建的微任务 => 主线程上创建的宏任务 => 微任务中创建的宏任务

    异步宏任务队列只有一个,当在微任务中创建一个宏任务之后,他会被追加到异步宏任务队列上(跟主线程创建的异步宏任务队列是同一个队列)

    // 宏任务1
    new Promise((resolve) => {
      console.log('new Promise(macro task 1)');
      resolve();
    }).then(() => {
      // 微任务1
      console.log('micro task 1');
      setTimeout(() => {
        // 宏任务3
        console.log('macro task 3');
      }, 0)
    })
    
    setTimeout(() => {
      // 宏任务2
      console.log('macro task 2');
    }, 1000)
    
    console.log('========== Sync queue(macro task 1) ==========');
    

    结果:

    ========== Sync queue(macro task 1) ==========
    micro task 1
    macro task 3
    macro task 2
    

    总结

    微任务队列优先于宏任务队列执行,微任务队列上创建的宏任务会被后添加到当前宏任务队列的尾端,微任务队列中创建的微任务会被添加到微任务队列的尾端。只要微任务队列中还有任务,宏任务队列就只会等待微任务队列执行完毕后再执行。

    最后上一张几乎涵盖基本情况的例图和例子

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E9JbttZi-1622687528232)(https://ws1.sinaimg.cn/large/a71efaafly1g232hxfbhrj21350h9406.jpg)]

    console.log('======== main task start ========');
    new Promise(resolve => {
      console.log('create micro task 1');
      resolve();
    }).then(() => {
      console.log('micro task 1 callback');
      setTimeout(() => {
        console.log('macro task 3 callback');
      }, 0);
    })
    
    console.log('create macro task 2');
    setTimeout(() => {
      console.log('macro task 2 callback');
      new Promise(resolve => {
        console.log('create micro task 3');
        resolve();
      }).then(() => {
        console.log('micro task 3 callback');
      })
      console.log('create macro task 4');
      setTimeout(() => {
        console.log('macro task 4 callback');
      }, 0);
    }, 0);
    
    new Promise(resolve => {
      console.log('create micro task 2');
      resolve();
    }).then(() => {
      console.log('micro task 2 callback');
    })
    
    console.log('======== main task end ========');
    

    结果:

    ======== main task start ========
    create micro task 1
    create macro task 2
    create micro task 2
    ======== main task end ========
    micro task 1 callback
    micro task 2 callback
    macro task 2 callback
    create micro task 3
    create macro task 4
    micro task 3 callback
    macro task 3 callback
    macro task 4 callback
    
    展开全文
  • C# Task任务队列

    千次阅读 2021-05-28 14:25:31
    目录 一、需求 二、基本的Task用法 三、让Task任务按顺序执行 四、使用异步委托解决UI界面卡死问题 五、异步任务队列按顺序执行 六、封装任务队列 七、封装任务队列优化版 结束 一、需求 众所周知,方法体内代码是从...

    目录

    一、需求

    二、基本的Task用法

    三、让Task任务按顺序执行

    四、使用异步委托解决UI界面卡死问题

    五、异步任务队列按顺序执行

    六、封装任务队列

    七、封装任务队列优化版

    结束


    一、需求

    众所周知,方法体内代码是从上往下执行的,在我们工作中经常会遇到一些需要延时执行,但又必须按顺序来执行的需求。这要怎么解决呢。微软官方提供的Task API就是专门来解决这个问题的。那么下面就开始吧。

    二、基本的Task用法

    新建一个Winfrom项目

    using System;
    using System.Collections.Generic;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace 线程2
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
                Task task1 = new Task(() =>
                {
                    Thread.Sleep(400);
                    Console.WriteLine("task1");
                });
                Task task2 = new Task(() =>
                {
                    Thread.Sleep(300);
                    Console.WriteLine("task2");
                });
                Task task3 = new Task(() =>
                {
                    Thread.Sleep(200);
                    Console.WriteLine("task3");
                });
                Task task4 = new Task(() =>
                {
                    Thread.Sleep(100);
                    Console.WriteLine("task4");
                });
                task1.Start();
                task2.Start();
                task3.Start();
                task4.Start();
            }
        }
    }
    

    运行:

    由于各个任务内部延时不同,最先执行的Task1,反而最后一个执行完,如果既要做延时操作,又要求从任务按顺序执行,要怎么解决呢?

    三、让Task任务按顺序执行

    修改代码:

    using System;
    using System.Collections.Generic;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace 线程2
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private List<Task> TaskList = new List<Task>();
    
            private void Form1_Load(object sender, EventArgs e)
            {
                Task task1 = new Task(() =>
                {
                    Thread.Sleep(400);
                    Console.WriteLine("task1");
                });
                Task task2 = new Task(() =>
                {
                    Thread.Sleep(300);
                    Console.WriteLine("task2");
                });
                Task task3 = new Task(() =>
                {
                    Thread.Sleep(200);
                    Console.WriteLine("task3");
                });
                Task task4 = new Task(() =>
                {
                    Thread.Sleep(100);
                    Console.WriteLine("task4");
                });
    
                TaskList.Add(task1);
                TaskList.Add(task2);
                TaskList.Add(task3);
                TaskList.Add(task4);
    
                foreach (Task task in TaskList)
                {
                    task.Start();
                    task.Wait();
                }
            }
        }
    }
    

    运行:

    用上面的方法虽然有效,你可以看看,点击界面的时候,界面处鼠标指针会一直转圈,导致winfrom界面卡住,无法操作,这是因为使用Thread.Sleep 导致主线程阻塞,下面就来解决UI界面卡死的问题。

    四、使用异步委托解决UI界面卡死问题

    代码:

    using System;
    using System.Collections.Generic;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace 线程2
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
    
            private List<Task> TaskList = new List<Task>();
    
    
            private void Button_Calculate_Click(object sender, EventArgs e)
            {
                Task task1 = new Task(async () =>
                {
                    await Task.Delay(TimeSpan.FromSeconds(4));
                    Console.WriteLine("task1");
                });
                Task task2 = new Task(async () =>
                {
                    await Task.Delay(TimeSpan.FromSeconds(3));
                    Console.WriteLine("task2");
                });
                Task task3 = new Task(async () =>
                {
                    await Task.Delay(TimeSpan.FromSeconds(2));
                    Console.WriteLine("task3");
                });
                Task task4 = new Task(async () =>
                {
                    await Task.Delay(TimeSpan.FromSeconds(1));
                    Console.WriteLine("task4");
                });
    
                TaskList.Add(task1);
                TaskList.Add(task2);
                TaskList.Add(task3);
                TaskList.Add(task4);
    
                foreach (Task task in TaskList)
                {
                    task.Start();
                    task.Wait();
                }
            }
        }
    }
    

    运行:

    用异步方式虽然界面不会卡住,但另一个问题来了,task.wait()方法似乎没有效果。里面的任务队列依然没有按顺序来执行。那么如何即使用异步执行,也不阻塞主线程,而且要任务按顺序来执行呢?

    五、异步任务队列按顺序执行

    代码:

    private void Test()
    {
        Task.Run(() =>
        {
            Task t1 = new Task(() => {
                Thread.Sleep(2000);
                Console.WriteLine("t1");
                num = 1;
            });
            t1.Start();
            t1.Wait();
            Task t2 = new Task(() => {
                Thread.Sleep(1000);
                Console.WriteLine("t2");
                num = 3;
            });
            t2.Start();
            t2.Wait();
            Console.WriteLine("线程执行完毕");
        });
    }

    运行:

    效果是实现了,代码看起来好搓啊,强迫症都犯了,没关系,可以使用更优雅的写法:

    private async void Test()
    {
        await Task.Run(async () =>
        {
            await Task.Delay(4000);
            Trace.WriteLine("第1个线程执行");
        });
        await Task.Run(async () =>
        {
            await Task.Delay(3000);
            Trace.WriteLine("第2个线程执行");
        });
        await Task.Run(async () =>
        {
            await Task.Delay(2000);
            Trace.WriteLine("第3个线程执行");
        });
    }

    运行:

    到此为止,功能就实现了,这个需求在Unity3d中使用协程很简单的几句就可以搞定,但在Winfrom等项目的开发中,确实有点繁琐。

    六、封装任务队列

    下面的代码我不认为是一个很好的写法,需要添加任务后,还得手动去调用,如果能添加到任务队列就不管了,让其自己自动按顺序来执行任务,岂不是更好,读者如果有兴趣自己去完善这个猜想。另外,在游戏开发中,比如RGP项目中,有专门的任务系统,它和我这个帖子的概念不能混为一谈,RPG任务系统更多的偏向数据的存取,来获取任务的完成状态。

    using System;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    
    namespace Utils
    {
        public class TaskQueue
        {
            /// <summary>
            /// 任务列表
            /// </summary>
            private List<Task> TaskList = null;
            /// <summary>
            /// 是否在执行任务中
            /// </summary>
            private bool isPerformTask = false;
            /// <summary>
            /// 执行完任务的回调
            /// </summary>
            public Action CallBack = null;
    
    
            private static TaskQueue _instance = null;
            public static TaskQueue Instance
            {
                get
                {
                    if (_instance == null)
                        _instance = new TaskQueue();
                    return _instance;
                }
            }
    
            /// <summary>
            /// 添加任务
            /// </summary>
            /// <param name="task"></param>
            public void AddTask(Task task)
            {
                if (isPerformTask)
                {
                    Console.WriteLine("[TaskQueue]任务正在执行中,此时不能做赋值操作");
                    return;
                }
    
                if (task != null)
                {
                    TaskList.Add(task);
                }
            }
    
            /// <summary>
            /// 执行任务
            /// </summary>
            public void PerformTask()
            {
                if (isPerformTask)
                {
                    Console.WriteLine("[TaskQueue]任务正在执行中,不可重复调用");
                    return;
                }
                if (TaskList == null || TaskList.Count == 0)
                {
                    Console.WriteLine("[TaskQueue]任务列表为空");
                    return;
                }         
    
                Task.Run(() =>
                {
                    isPerformTask = true;
    
                    foreach (Task item in TaskList)
                    {
                        item.Start();
                        item.Wait();
                    }
    
                    TaskList.Clear();
                    isPerformTask = false;
    
                    if (CallBack != null) CallBack();
                });
            }
    
            private TaskQueue()
            {
                TaskList = new List<Task>();
            }
        }
    }
    

    调用:

    Task task1 = new Task(() =>
    {
        Thread.Sleep(1000);
        Console.WriteLine("t1");
    });
    Task task2 = new Task(() =>
    {
        Thread.Sleep(2000);
        Console.WriteLine("t2");
    });
    Task task3 = new Task(() =>
    {
        Console.WriteLine("t3");
    });
    Action callback = () =>
    {
        Console.WriteLine("所有任务执行完成");
    };
    TaskQueue.Instance.AddTask(task1);
    TaskQueue.Instance.AddTask(task2);
    TaskQueue.Instance.AddTask(task3);
    TaskQueue.Instance.CallBack = callback;
    TaskQueue.Instance.PerformTask();

    运行:

    七、封装任务队列优化版

    2022.07.26 优化,和上面版本的区别是,任务添加完成后,会自动调用。

    执行任务队列,任务会一个个执行,中间可等待,并且不会阻塞主线程,在运行的时候,可以向任务队列中添加任务,不会影响任务的执行,

    代码:

    using System;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    
    namespace Utils
    {
        public class TaskQueue
        {
            /// <summary>
            /// 任务队列
            /// </summary>
            private Queue<TaskData> QueuesTask = new Queue<TaskData>();
            /// <summary>
            /// 任务队列是否在执行中
            /// </summary>
            private bool isExecuteing = false;
    
            private static TaskQueue _instance = null;
            public static TaskQueue Instance
            {
                get
                {
                    if (_instance == null)
                        _instance = new TaskQueue();
                    return _instance;
                }
            }
    
            /// <summary>
            /// 任务是否进行中
            /// </summary>
            /// <returns></returns>
            public bool IsTasking()
            {
                return isExecuteing;
            }
    
            /// <summary>
            /// 添加任务,任务会按照队列自动执行
            /// </summary>
            /// <param name="task"></param>
            public void AddTaskAndRuning(TaskData taskData)
            {
                if (taskData == null) return;
    
                QueuesTask.Enqueue(taskData);
    
                StartPerformTask();
            } 
    
            /// <summary>
            /// 执行任务
            /// </summary>
            private async void StartPerformTask()
            {
                if (isExecuteing) { return; }
    
                while (QueuesTask.Count > 0)
                {
                    isExecuteing = true;
                    await Task.Run(() =>
                    {
                        TaskData taskDatas = QueuesTask.Dequeue();
                        Task task = taskDatas.Tasks;
                        task.Start();
                        task.Wait();
                        if (taskDatas.CallBack != null) taskDatas.CallBack(null);
                    });
                }
    
                isExecuteing = false;
            }
    
            private TaskQueue()
            {
            }
        }
    
        public class TaskData
        {
            /// <summary>
            /// 任务名
            /// </summary>
            public string Name { get; set; }
            /// <summary>
            /// 任务
            /// </summary>
            public Task Tasks { get; set; }
            /// <summary>
            /// 任务完成后的回调
            /// </summary>
            public Action<string> CallBack { get; set; }
        }
    }
    

    调用:

    TaskData taskData2 = new TaskData();
    taskData2.Tasks = new Task(() =>
    {
        Thread.Sleep(4000);
        Console.WriteLine("[Form1]taskData2");
    });
    taskData2.CallBack = (string res) =>
    {
        Console.WriteLine("[Form1]taskData2执行完的回调");
    };
    TaskQueue.Instance.AddTaskAndRuning(taskData2);
    
    
    TaskData taskData3 = new TaskData();
    taskData3.Tasks = new Task(() =>
    {
        Thread.Sleep(5000);
        Console.WriteLine("[Form1]taskData3");
    });
    taskData3.CallBack = (string res) =>
    {
        Console.WriteLine("[Form1]taskData3执行完的回调");
    };
    TaskQueue.Instance.AddTaskAndRuning(taskData3);

    运行:

    结束

    如果这个帖子对你有用,欢迎给我点赞 + 留言,谢谢

    end

    展开全文
  • 消息队列和任务队列有什么区别?

    千次阅读 2020-11-03 22:46:19
    消息队列这个概念其实在我之前的文章:手把手教姐姐写消息队列,自己动手用go写一个简易版的消息队列,有兴趣的小伙伴们可以看一下这篇文章。回归正题,我们再来介绍一下什么是消息队列。 消息队列,一般我们会简称...
  • celery任务队列

    千次阅读 2020-03-08 16:55:30
    文章目录celery分布式任务队列一. celery 简介Celery 特性 :二. celery 组件1. Celery 扮演生产者和消费者的角色,2. 产生任务的方式 :3. celery 依赖三个库: 这三个库, 都由 Celery 的开发者开发和维护.三. 选择消息...
  • 事件循环 JavaScript 语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。为了协调事件、用户交互、脚本、UI 渲染和网络处理等行为,防止主线程的不阻塞,Event Loop 的方案应用而生。...任务队列
  • 在《阿里巴巴java开发手册》中写到,...允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。 2)CachedThreadPool 和 ScheduledThreadPool: 允许的创建线程数量为 Integer.MAX_VALUE,可能
  • Okhttp 双任务队列机制

    千次阅读 2022-01-19 16:58:45
    为了完成调度和复用,定义了两个队列分别用做等待队列(readyAsyncCalls)和执行任务(runningAsyncCalls)的队列。这两个队列都是Dispatcher成员变量。Dispatcher是一个控制执行,控制全部Call的分发和任务的调度、...
  • 事件循环与任务队列 是JS中比较重要的两个概念,在ES6中,清楚的区分宏观任务和微观任务队列才能解释Promise的一些表现。 js是单线程语言,对于异步操作只能先把它放在一边,按照某种规则按先后顺序放进一个容器...
  • Go 实现任务队列

    千次阅读 2020-07-23 10:31:50
    问题提出 当某个对象的接口仅能在单线程(协程)调用时, 所有针对该对象的接口调用都应该处于同一个调度...一个存放任务的队列,一个用于任务队列的资源锁, 一个单独的内部线程 内部线程不断的取出队列中的新任务执行
  • java多线程任务队列模型

    千次阅读 2018-11-08 16:59:45
    此篇文章将从任务队列的设计;任务调度的方式(串行和并行)。代码很简单,主要是设计的思想。 任务队列 final class PendingPostQueue {  // 含有头、尾指针的链表结构实现队列  private PendingPost head;  ...
  • Redis应用之任务队列

    千次阅读 2019-03-17 13:54:35
    Redis实现任务队列 1.任务队列 松耦合性   生产者和消费者无需知道彼此的实现细节,只需要约定好任务的描述格式,这使得生产者和消费者可以由不同的团队使用不同的编程语言编写。 易于扩展   消费者可以有多个,...
  • 线程池中的任务队列

    千次阅读 2020-10-01 14:39:15
    该参数是指被提交但未执行的任务队列,它是一个BlockingQueue接口的对象,用于存放Runable对象。根据功能分类,在ThreadPoolExecutor类的构造函数中可使用以下几种BlockingQueue接口。 直接提交的队列:该功能有...
  • 用标准C++实现任务队列

    千次阅读 2018-11-22 13:47:59
    下面介绍一个简单的任务队列,查看完整代码。 在实现任务队列前需要定义一个接口与一个工具类 任务接口:子类实现接口的run方法来处理具体任务。 自旋锁类:用于保护任务队列的并发访问(用C++11原子操作实现)。...
  • 一个 串行 的任务队列: 利用 QThread run 的 event loop,来实现任务调度。 Created with Raphaël 2.1.2 开始 传入待执行任务 将待执行的任务放进 FIFO 队列里 检查启动线程 发出执行任务信号 线程收到...
  • ThreadPoolExecutor参数解析 之前学习线程池,发现线程池大致有四种创建方法: ...newScheduledThreadPool 创建一个可周期性调度任务的线程池 public static ExecutorService newFixedThreadPool(int nThreads
  • JavaScript任务队列的顺序机制(事件循环)

    千次阅读 多人点赞 2019-05-28 19:35:06
    如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务,以此类推。 这种模式的好处是实现起来比较简单,执行环境相对单纯;坏处是只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序...
  • JS中的任务队列(详解)

    千次阅读 2020-10-21 19:56:45
    说起任务队列的话,首先我们要回顾一下JS语言的特点。 我们知道,Javascript 这门脚本语言诞生的使命就是为处理页面中用户的交互,以及操作 DOM 而诞生的。 所以JS的设计就是单线程的,总不能多线程来操作DOM结构吧...
  • C#任务队列的实现

    热门讨论 2012-10-30 10:42:59
    用C#实现任务队列,一个队列存放任务,线程互斥的从任务队列中取,放任务,任务队列为空,线程等待,直到有任务加入队列为止。
  • Java几种线程池及任务队列

    千次阅读 2020-10-01 14:15:57
    Java几种线程池及任务队列 JDK提供了一套Executor框架,该框架提供了多种类型的线程池,主要的有一下工厂方法: //该方法返回一个固定线程数量的线程池。该线程池中的线程数量始终不变。 public static ...
  • 开源一个用Kotlin实现的任务队列 开源仓库地址
  • Redis——任务队列

    千次阅读 2019-01-27 23:56:00
    很多博客网站中都会有发送邮件这个功能,发送邮件是一个双向数据的交互过程,如果使用单线程实现,很难避免会... 通知的过程可以借助任务队列来实现。与任务队列交互的类有两种:一类是生产者,另一类是消费者。生...
  • 任务队列简单实现

    千次阅读 2019-03-27 19:18:02
    实用场景: 例子1: 例子2: 生产者-----消费者 之间 C/C++ .h #ifndef __TASK_QUEUE_H__ #define __TASK_QUEUE_H__ ... // 任务处理函数 void* param; // 附加参数 }Task_t; ty...
  • golang 任务队列(生产者消费者模型)

    千次阅读 2020-01-02 14:52:55
    这段时间在做一个zfb在线支付项目, 用到了任务队列, 索性就用生产者消费者模型简单的撸了一把;不足之处, 请多多指教. 1, 文件结构如下: 2, taskqueue.go 代码如下: package taskqueue import ( "container/...
  • 写这篇博文的起因是,我在论坛宣传我开源的新项目YTask(go语言异步任务队列)时,有小伙伴在下面回了一句“为什么不用nsq?”。这使我想起,我在和同事介绍celery时同事说了一句“这不就是kafka吗?”。 那么YTask...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 531,812
精华内容 212,724
关键字:

任务队列

友情链接: Commande MLI _PWM_.rar