最近,咱们团队为了进一步提高合作效率,组织了一次趣味分享流动,心愿通过游戏的形式,帮忙技术部门的共事们更好地了解和实际麻利开发的办法。

在这次流动中,“哪种口头形式更麻利”、“为什么采纳这种办法”等关乎麻利概念实践和实际办法的思考被搭档们提出来并公开探讨。作为开发小组的成员,我获益颇多,特将此次流动中的思考总结下来分享给大家,独特成长~

游戏规则

10集体翻30张牌,每个人要把这30张牌的每1张牌都翻一遍,计算第1集体翻完30张牌所消耗的工夫和所有人翻完30张牌所消耗的工夫~

假如每一个红色方块耗时x,每一个橙色方块耗时y,每一个黄色方块耗时z (x, y, z > 0)

计划1: 第n集体必须等第n-1集体翻完所有的30张牌能力开始翻牌,第1集体不必等

那么咱们参考上图的构造,先计算第1~5集体的翻完30张牌的工夫,而后再乘以2就是总计用时(不存在影响工夫的意外状况):

T1 = ((5 + 1) 5 / 2 x + (4 + 1) 4 / 2 y + 25 5 z) * 2 =30x + 20y + 250z

计划2:第n集体必须等第n-1集体翻完第5张牌能力开始翻牌,第1集体不必等;且第n集体必须等第n-1集体翻完第m张牌,能力翻第m张牌,第1集体不必等。

参考上图构造,先计算1 ~ 10集体翻完前5张牌的工夫,而后再计算第10集体翻完6 ~ 25张牌的工夫就是总计用时(不存在影响工夫的意外状况):

T2= ((5 + 1) 5 / 2 x + (4 + 1) 4 / 2 y) 2 + 25 z = 30x + 20y + 25z

计划3:第n集体必须等第n-1集体翻完第m张牌,能力翻第m张牌,第1集体不必等。

参考上图构造:先计算1 ~ 10集体翻完第1张牌的工夫,而后再计算第10集体翻完第2 ~ 5张牌的工夫,最初再加上第10集体翻完第6 ~ 30张牌的工夫就是总计用时(不存在影响工夫的意外状况):T3= 10x + 4y + 25z

最终后果

上面咱们用程序来验证论断的正确性。
假如 x = y = z = 1s,那最终后果应该是:

T1 = 30 + 20 + 250 = 300s

T2 = 30 + 20 + 25 = 75s

T3 = 10 + 4 + 25 = 39s

理论后果:

public class AgileTest {    private static final Logger LOGGER = LoggerFactory.getLogger(AgileTest.class);    public static void main(String[] args) {        long time1 = way1();        long time2 = way2();        long time3 = way3();        LOGGER.info("time1: {} ms", time1);        LOGGER.info("time2: {} ms", time2);        LOGGER.info("time3: {} ms", time3);    }    /**     * <p>计划1</p>     * <p>第n集体必须等第n-1集体翻完所有的30张牌能力开始翻牌,第1集体不必等。</p>     * @return 耗时 ms     */    public static long way1() {        final String way = "way1";        long startTime = System.currentTimeMillis();        // 1.10集体        for (int i = 1; i < 11; i++) {            AtomicInteger atomicI = new AtomicInteger(i);            // 2.30张牌,每个人翻完30张牌,下集体能力开始            for (int j = 1; j < 31; j++) {                node(way, atomicI, j);            }        }        long endTime = System.currentTimeMillis();        return endTime - startTime;    }    /**     * <p>计划2</p>     * <p>第n集体必须等第n-1集体翻完第5张牌能力开始翻牌,第1集体不必等;且第n集体必须等第n-1集体翻完第m张牌,能力翻第m张牌,第1集体不必等。</p>     * @return 耗时 ms     */    public static long way2() {        final String way = "way2";        long startTime = System.currentTimeMillis();        CountDownLatch latch = new CountDownLatch(10);        Map<Integer, Integer> map = new ConcurrentHashMap<>();        // 1.10集体        for (int outUser = 1; outUser < 11; outUser++) {            int outLastUser = outUser - 1;            Integer lastOutUserNode = 0;            // 2.每个人必须等后面那个人翻完5张牌能力开始翻牌,第1集体例外            while (outUser != 1 && ((lastOutUserNode = map.get(outLastUser)) == null || lastOutUserNode < 5)) {            }            AtomicInteger atomicI = new AtomicInteger(outUser);            Thread thread = new Thread(() -> {                try {                    int innerUser = atomicI.get();                    int lastInnerUser = innerUser - 1;                    // 3.30张牌                    for (int j = 1; j < 31; j++) {                        // 4.翻牌的速度不能超过前1集体,第1集体例外,第30张除外                        Integer lastInnerUserNode = 0;                        while (innerUser != 1 && ((lastInnerUserNode = map.get(lastInnerUser)) == null || lastInnerUserNode < j)) {                        }                        node(way, atomicI, j);                        map.put(innerUser, j);                    }                } catch (Exception e) {                    LOGGER.error("Current Thread: " + Thread.currentThread().getName() +  "+, exception: ", e);                } finally {                    latch.countDown();                }            }, "thread-user-" + outUser);            thread.start();        }        try {            latch.await();        } catch (InterruptedException e) {            LOGGER.error("wait thread exception: ", e);        }        long endTime = System.currentTimeMillis();        return endTime - startTime;    }    /**     * <p>计划3</p>     * <p>第n集体必须等第n-1集体翻完第m张牌,能力翻第m张牌,第1集体不必等。</p>     * @return 耗时 ms     */    public static long way3() {        final String way = "way3";        long startTime = System.currentTimeMillis();        CountDownLatch latch = new CountDownLatch(10);        Map<Integer, Integer> map = new ConcurrentHashMap<>();        // 1.10集体        for (int outUser = 1; outUser < 11; outUser++) {            AtomicInteger atomicI = new AtomicInteger(outUser);            Thread thread = new Thread(() -> {                try {                    int innerUser = atomicI.get();                    int lastInnerUser = innerUser - 1;                    // 2.30张牌                    for (int j = 1; j < 31; j++) {                        // 3.翻牌的速度不能超过前1集体,第1集体例外                        Integer lastInnerUserNode = 0;                        while (innerUser != 1 && ((lastInnerUserNode = map.get(lastInnerUser)) == null || lastInnerUserNode < j)) {                        }                        node(way, atomicI, j);                        map.put(innerUser, j);                    }                } catch (Exception e) {                    LOGGER.error("Current Thread: " + Thread.currentThread().getName() +  "+, exception: ", e);                } finally {                    latch.countDown();                }            }, "thread-user-" + outUser);            thread.start();        }        try {            latch.await();        } catch (InterruptedException e) {            LOGGER.error("wait thread exception: ", e);        }        long endTime = System.currentTimeMillis();        return endTime - startTime;    }    /**     * 执行节点     * @param atomicI 第i集体     * @param j 第j张牌     */    private static void node(String way, AtomicInteger atomicI, int j) {        int i = atomicI.get();        long currentTime = System.currentTimeMillis() / 1000;//        System.out.printf("[%s] %s i-j: %d-%d %d\n", Thread.currentThread().getName(), way, i, j, currentTime);        try {            if ((i >= 1 && i <= 5 && j >= 1 && j <= 5 && i + j <= 6)                    || (i >= 6 && i <= 10 && j >= 1 && j <= 5 && i + j <= 11)) {                Thread.sleep(1000);            } else if ((i >= 1 && i <= 5 && j >= 1 && j <= 5 && i + j > 6)                    || (i >= 6 && i <= 10 && j >= 1 && j <= 5 && i + j > 11)) {                Thread.sleep(1000);            } else if (j >= 6) {                Thread.sleep(1000);            }        } catch (Exception e) {            LOGGER.error("node sleep exception: ", e);        }    }}

日志输入:

17:52:10.645 [main] INFO com.peng.java_study.practice.zhikan.AgileTest - time1: 302746 ms17:52:10.648 [main] INFO com.peng.java_study.practice.zhikan.AgileTest - time2: 75632 ms17:52:10.648 [main] INFO com.peng.java_study.practice.zhikan.AgileTest - time3: 39348 ms

从日志中能够看出,理论后果与预期基本一致,多进去的几百毫秒是程序在运行过程中不可避免的耗费。由它们耗时可知:T3 < T2 < T1,所以在不思考其余因素影响的前提下,计划3是最麻利的!

深刻思考

在任何条件下,计划3都实用吗?

答案是否定的,在某些非凡状况下,计划3反而更慢!

假如:

第n - 1集体翻完1 ~ 30张牌后,一起交接给第n集体的筹备工夫和沟通工夫为a。那么最终耗时为:T1’= T1 + (10 - 1) * a =T1 + 9a

若第n - 1集体翻完第1 ~ 5张牌后,一起交接给第n集体时,须要筹备工夫和沟通工夫为b;第n - 1集体翻完第6 ~ 30张牌中的任意一张牌后,交接给第n集体时,须要的筹备工夫与沟通工夫c。那么最终耗时为:T2’= T2 + (10 - 1) b + 25 9 * c =T2 + 9b + 225c

第n - 1集体翻完1 ~ 30张牌中的任意一张牌后,交接给第n集体时,须要的筹备工夫与沟通工夫为d。那么最终耗时为:T3’= T_3 + 30 9 d = T3 + 270d

当初,咱们来验算一遍:

当「筹备工夫与沟通工夫」与「单个工作的执行工夫时」的大小满足肯定的条件时,计划3是否有可能比计划1慢?

假如T3’ > T1’,那么:

T3 + 270d > T1 + 9a 即 10x + 4y + 25z + 270d > 30x + 20y + 250z + 9a

再次假如 x = y = z = 1s,那么上式就等同于:

10 + 4 + 25 + 270d > 30 + 20 + 250 + 9a 即

d > (261 + 9a) / 270或a < (270d - 261) / 9

如果 d = 1s,那 a < 1s 就能够使计划1快于计划3…

由此能够得出结论:在肯定条件下,计划3未必是最优的,且这种状况很有可能产生…

最终论断

在大多数状况下,计划3会比计划1更麻利,但在上述两大节中的非凡状况下,计划3反而是最慢的。因而在实在的生存场景中,还是要“就地取材”,不能一概而论!

思考到这里并没有进行,更多探讨和分享能够期待“麻利小游戏的思考[下]”。
————————————————
LigaAI 新一代智能研发合作平台 让AI 为您的研发团队提供个性化、智能化的我的项目合作体验,化繁就简,帮忙开发者专一、高效的创作。