V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
morefreeze
V2EX  ›  程序员

遇到一个工人分工干活的问题

  •  
  •   morefreeze · 2017-02-28 17:32:32 +08:00 · 3253 次点击
    这是一个创建于 2826 天前的主题,其中的信息可能已经有所发展或是发生改变。

    假设我有 n 个工人,我可以让他们干活或者同步地检查别人是否完成了工作。

    有两个任务 A 和 B , B 需要有 m 个任务 A 完成了才能执行,所以我就要抽调 m 个工人去监工,但当 m>n 时,就会导致没有人实际在工作,就死锁了。

    但 n 不能设得>m ,因为如果有 m 个工人都在干活的话,内存会不够。

    请问这问题咋解决?

    目前我能想到的策略是降低监工的优先级,保证干活的人最先执行,让监工更快地返回结果,增加重试次数(相当于是个异步了)。说到底还是平衡监工和干活人的数量。

    10 条回复    2017-03-02 12:04:37 +08:00
    casparchen
        1
    casparchen  
       2017-02-28 19:06:48 +08:00 via iPhone
    完成工作后主动报告不好吗,为什么要监工
    snnn
        2
    snnn  
       2017-02-28 21:14:21 +08:00 via Android
    创建 task A 的时候传递一个原子类型的计数器进去。每完成一个就减一。减到 0 就 submit task B 。
    没有监工。 no wait
    exch4nge
        3
    exch4nge  
       2017-03-01 09:36:20 +08:00
    简单的解决方法就像 @snnn 写的一样,不用什么监工。
    复杂情况下,一般会安排一个工长(任务调度线程),负责分配任务, B 任务的前置条件如果没有满足,就不分配 B 任务。
    morefreeze
        4
    morefreeze  
    OP
       2017-03-01 12:07:16 +08:00
    @casparchen 老哥你这话说的就像问:我的程序慢咋办啊?加内存加机器就好了啊。在目前的框架下无法做到异步的
    @snnn @exch4nge 靠点谱,我也许可以找些别的方法把监控 m 个任务改成监控一个变量 m ,当然也要保证 m 会被正确地减去,比如我原先要求[1,2,3,4,5]完成,而[1,2,2,4,5]虽然也是 5 个,但完成的人不对也不行。
    exch4nge
        5
    exch4nge  
       2017-03-01 13:36:33 +08:00
    @morefreeze 所以你还是没在题目里描述清楚为什么需要监工以及 A 、 B 任务相关的详细信息。你没有把问题描述清楚,那 @snnn 跟我说的不能说不靠谱吧。
    按你这个评论的意思就是工人也有区分?却任务 A 是一样的任务 A ?那要求[1,2,3,4,5],就不能是[1,6,2,4,5]?
    Youen
        6
    Youen  
       2017-03-01 14:05:11 +08:00
    morefreeze
        7
    morefreeze  
    OP
       2017-03-01 16:02:43 +08:00
    @exch4nge (你们说的)靠点谱,你咋就理解成贬义呢,我的意思就是你们说的有些道理,给了我启发
    至于我最后说的[1,2,3,4,5]还是无视掉吧,我确实没在题目中说明,我只是自言自语提醒自己注意这个情况。
    另外回下你在 3 楼的方法,你说的其实就是“我”的工作,我就是一个调度器,我在指挥工人做事(包括干活和监视别人),你说检查任务 B 前置条件是否满足实际就是派工人去监工,但因为用的框架所限,他是同步阻塞的,我让一个工人去监工了,那这个工人只能等着,啥都干不了。

    多说点,我说监工的是 airflow 中的 ExternalTaskSensor ,干活指可以执行功能的 Operator (比如 BashOperator ),避免过多背景介绍,抽象成了这个问题
    https://airflow.incubator.apache.org/code.html?highlight=response#airflow.operators.ExternalTaskSensor
    snnn
        8
    snnn  
       2017-03-01 18:35:57 +08:00 via Android
    @morefreeze 你脑子转个弯啊。假如 worker 有 ID 区分,那把 int 换成 set<int>就行了
    exch4nge
        9
    exch4nge  
       2017-03-01 21:48:07 +08:00   ❤️ 1
    @morefreeze 首先对“靠点谱”的贬义理解道个歉,刚刚花半小时看了下 airflow ,之前没接触过,下面我说的可能会有错误。
    Airflow 本身就是一个对任务进行规划、定期执行的框架,我看到 DAG 是可以规划多个任务及依赖关系。
    不过看你用了 ExternalTaskSensor ,估计是没办法把任务 A 与任务 B 放到一个 DAG 里,如果能放在一个 DAG 里那更简单了。
    其实不考虑 airflow 这个背景框架,确实可以用一个数据结构来存储 task 的完成情况,例如 @snnn 说的那样,然后保证这个数据结构的读写是原子操作就可以了,不过这个就限制在同一个进程内了( airflow 可能不是吧, airflow 是不是分布式的?)。
    在 airflow 这个框架背景下,可以用框架提供的 XComs 做 task 间通信,原来的监工 task 可以改成一个,不用 ExternalTaskSensor ,而是通过收集其它 task 发来的信息,等待合适时机,发布任务 b 。
    https://issues.apache.org/jira/browse/AIRFLOW-47 好像情况稍微类似。
    morefreeze
        10
    morefreeze  
    OP
       2017-03-02 12:04:37 +08:00
    @snnn 对对对,是这么想的,但其实我是要知道 worker 执行的 task ID ,这个问题我自己能解决
    @exch4nge 感谢热心帮助,其实没必要去了解这些
    放在一个 DAG 肯定是可以的,但这就像一个项目也可以把代码放在一个文件里一样
    airflow 是可以分布式执行,但比如任务信息这些都存在数据库里,由一个 scheduler 来统一管理
    XComs 也是种解决办法,我觉得可行。
    我在 sto 上提问也得到了比较好的解决办法, http://stackoverflow.com/questions/42504185/airflow-celery-worker-will-be-blocked-if-sensor-number-large-than-concurrency/42510574#42510574
    利用 Pool 来限制 ExternalTaskSensor 最大执行数量,这样相当于把监工和工人隔离开了,我之前也不知道有这个技巧。

    总结下这个问题思路:
    划分监工和工人的执行,比如 Pool 的概念,或者启两个 scheduler 分别管理监工和工人(从根本解决问题)
    进程间通信(解决问题,增加复杂度)
    配置一个较好的重试策略,调低监工优先级,监工较快返回结果,较多的重试(理论上点背的话还是会死锁,但降低概率)
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1097 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 18:25 · PVG 02:25 · LAX 10:25 · JFK 13:25
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.