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

Java 求解如何优化 100 个 if 判断?

  •  
  •   whereisgungun · 2022-11-07 21:04:51 +08:00 · 7612 次点击
    这是一个创建于 745 天前的主题,其中的信息可能已经有所发展或是发生改变。
    需求是这样的:
    上游服务调用接口( TCP 协议,用 netty 做了服务端,上游是客户端)发来报文,这个报文里面会有 35 个属性,我们简单定义这 35 个属性为 A 、B 、C 、D....然后每个属性的值为 a 、b 、c 、d....现在有接近 100 个模板,然后我们的功能就是要根据报文来确定要用哪一个,重点是这 100 个模板是没有规律的。

    比如:
    if(a==1 && b==2) {return "模板 1";}
    if(c.length==1 && d.equals("xxx")) {return "模板 2";}
    ...
    也就是说,会有 100 个 if 判断来确定此次调用的报文对应哪个模板,而且报文是不冲突的,35 个属性的值只要命中其中一个模板,其他的就都不符合,都是互斥的。(算是 CompletableFuture 的 anyOf 方法。)

    现在暂时找不出这 100 个 if 里面有什么具体的规律,35 个属性也没有。求问各位大神有什么好的思路优化吗?线程池 or 中间件?

    PS:作为最底层的外包,也没法要求上游能做什么改动了。。他们是一个老旧的银行系统,以前也是用的一个一个判断来着,现在把项目丢给我们了。。
    82 条回复    2022-11-09 12:56:51 +08:00
    nightwitch
        1
    nightwitch  
       2022-11-07 21:09:21 +08:00 via Android
    没规律的话 100 个判断是少不了的,只是写成 if 和写成函数的区别
    hqs0417
        2
    hqs0417  
       2022-11-07 21:11:32 +08:00
    可以考虑做个规则引擎,类似查表
    secondwtq
        3
    secondwtq  
       2022-11-07 21:12:17 +08:00
    你是想要优化结构还是优化性能?
    ClericPy
        4
    ClericPy  
       2022-11-07 21:14:01 +08:00
    本来还以为路径那样前缀树, 一看还有判断长短....


    解释器模式搞个规则引擎吧
    hidemyself
        5
    hidemyself  
       2022-11-07 21:15:27 +08:00
    完全没规律如果后续也不会有什么改动,if 就可以了
    whereisgungun
        6
    whereisgungun  
    OP
       2022-11-07 21:16:35 +08:00
    @nightwitch 是的。知道得写了。。就是想问问有什么技术方法可以加快一下判断,压榨机器。。
    justNoBody
        7
    justNoBody  
       2022-11-07 21:16:57 +08:00
    无意冒犯,但如果只是作为人力外包,且领导没有明确要求重构、或者不给重构工时、或者不给充分的测试时间,千万别改这这部分的代码,在这 100 个 if-else 之上写新的业务逻辑就行,这部分你可以适当设计一下。
    whereisgungun
        8
    whereisgungun  
    OP
       2022-11-07 21:17:13 +08:00
    @secondwtq 主要还是性能
    optional
        9
    optional  
       2022-11-07 21:18:35 +08:00 via iPhone   ❤️ 8
    统计下各个模板的频率,把常见的模板放最上面,可以提高性能
    secondwtq
        10
    secondwtq  
       2022-11-07 21:18:52 +08:00
    @whereisgungun 有相关数据的话就简单,找出每个请求走的哪个 if ,命中频率最高的排前面就行
    whereisgungun
        11
    whereisgungun  
    OP
       2022-11-07 21:22:46 +08:00
    @optional
    @secondwtq
    感谢感谢,感觉还是得搞完之后再进行统计了
    whereisgungun
        12
    whereisgungun  
    OP
       2022-11-07 21:23:31 +08:00
    @hidemyself
    @justNoBody
    是的,时间不够性能优化的话就只能往这坨东西上面继续拉了
    whereisgungun
        13
    whereisgungun  
    OP
       2022-11-07 21:24:04 +08:00
    @hqs0417
    @ClericPy
    感谢,我去研究研究咋用
    xyjincan
        14
    xyjincan  
       2022-11-07 21:29:03 +08:00 via Android
    map 对象
    PendingOni
        15
    PendingOni  
       2022-11-07 21:30:13 +08:00
    #9 说的对,先把频率出现最高的放到最前面,之后用 swich 分组试试
    sparky
        16
    sparky  
       2022-11-07 21:59:13 +08:00 via Android
    可以试试决策树,有 java 开源实现,还可以可视化编辑,最终会生成一个 json 配置,可以实现规则和业务的分离
    ajaxgoldfish
        17
    ajaxgoldfish  
       2022-11-07 22:00:42 +08:00
    能不能多起几个线程
    546L5LiK6ZOt
        18
    546L5LiK6ZOt  
       2022-11-07 22:06:01 +08:00
    如果完全没有规律,那上游是怎么发报文的,也是 100 个 if ?我猜应该是有规律的,不然这一整条链路维护起来都很吐血。。。
    pannanxu
        19
    pannanxu  
       2022-11-07 22:09:17 +08:00
    直接枚举啊,一个参数是参数校验,一个参数是模板
    seers
        20
    seers  
       2022-11-07 22:26:16 +08:00
    试试图那些算法,DFS 和 BFS ,感觉会有效果
    CEBBCAT
        21
    CEBBCAT  
       2022-11-07 22:38:15 +08:00
    无非是些 if-else ,怎么会有性能问题呢?
    楼主的文字我都读了,但是总是不敢相信事实就是我理解的那样。假如这 35 个 field 之间几乎没有关系(除了文中提到的 c 、d )

    我认为现在楼主的诉求还是不明确,对问题的理解,或者说抽象还是不到位。为避免 XY 问题,楼主可否再多透露些细节?

    如果不方便的话,我认为有两个要点,一个是提高可维护性,上百个 if-else 会把人搞得头晕脑胀,不沐浴焚香在脑袋里装图灵机是 hold 不住这样的代码的。另一个是防止业务人员提错需求,维护人员照做之下产生逻辑覆盖错误
    billlee
        22
    billlee  
       2022-11-07 22:43:57 +08:00
    没有什么好有优化的,我做过规则引擎,100 个 if 编译出来的结果是运行速度最快的。
    jeesk
        23
    jeesk  
       2022-11-07 22:48:34 +08:00
    @seers 请教一下,dfs, bfs 如何应用到这种判断上去?

    说说我的看法, 要么用有优先级的过滤器判断, 要么就 if else.
    wangritian
        24
    wangritian  
       2022-11-07 23:01:39 +08:00   ❤️ 1
    别动,别动,别动
    Hurriance
        25
    Hurriance  
       2022-11-07 23:41:19 +08:00
    不用优化吧。优化后有回归测试的成本和发布风险,每个 if 写好注释,我觉得就可以了
    graptioute
        26
    graptioute  
       2022-11-07 23:45:19 +08:00
    表驱动编程
    JohnBull
        27
    JohnBull  
       2022-11-07 23:49:11 +08:00
    Erlang 的 pattern matching 最善于处理这种逻辑
    shyangs
        28
    shyangs  
       2022-11-08 00:02:29 +08:00
    對方是「老舊」的銀行系統,

    如果需求已經「固定」,這些條件屬性範本都不會再更動,

    那直接 if-else 性能應該是最高的,絕對比你用函數跳轉高。
    fkdog
        29
    fkdog  
       2022-11-08 00:10:21 +08:00
    这 100 个 if ,我就想单测能不能覆盖到所有的 case 。。。
    oneisall8955
        30
    oneisall8955  
       2022-11-08 00:10:28 +08:00 via Android
    JAVA 的话,可以把条件+模板组合封装成 Predicate ,用 stream.filter 出匹配到的,但这对性能没有优化
    allenzhangSB
        31
    allenzhangSB  
       2022-11-08 00:17:32 +08:00   ❤️ 2
    你一百多个 if else 能有什么性能问题?
    night98
        32
    night98  
       2022-11-08 00:20:20 +08:00
    你要搞清楚你调整代码的目的是啥,是更好的性能还是更好的可读性,还是更好的可修改性。更好的性能就是拆成三五个 func ,并发去调。可读性就是拆成枚举直接遍历,枚举里放判断的 func ,可修改性同上,加个 unit test 完事,要是没这些需求就别动,慢慢往上加 if 吧
    aguesuka
        33
    aguesuka  
       2022-11-08 00:36:30 +08:00   ❤️ 1
    @optional 按照楼主说的报文不冲突, 命中其中一个模板, 其他都不符合, 改顺序会影响结果.
    c0xt30a
        34
    c0xt30a  
       2022-11-08 07:10:57 +08:00
    1. 别动
    2. 表驱动
    3. 代码自动生成
    sorcerer
        35
    sorcerer  
       2022-11-08 07:46:45 +08:00 via iPhone   ❤️ 12
    if else 优化口诀
    互斥条件表驱动
    嵌套条件校验链
    短路条件早 return
    零散条件可组合
    opengps
        36
    opengps  
       2022-11-08 09:15:15 +08:00
    才 100 个,及即使按照高频率靠前优化了,效率也不会明显提升的,仅仅是少 100 个 if (假设条件里不带消耗性能的转换),测试不出来明显的感受。楼主跑个 1000 万次看看总时间,就知道效率优化有多小了
    allenzhangSB
        37
    allenzhangSB  
       2022-11-08 09:29:50 +08:00
    @night98 就 100 多个 if 判断, 多线程只会变慢
    312ybj22
        38
    312ybj22  
       2022-11-08 09:32:07 +08:00
    你先把规则进行统计,用规则树的形式进行统计(条件桩,条件项等),然后把规则写到规则引擎中(drools), 可以用数据脚本的形式,或者 excel 的形式。 这对于条件判断来讲就够了,当然我说的都是纸上谈兵,关键是能不能落地到你的业务体系中,你可以试试看,弄好的话还可以出去吹吹牛
    summerLast
        39
    summerLast  
       2022-11-08 09:37:52 +08:00
    责任链
    debuggerx
        40
    debuggerx  
       2022-11-08 09:46:45 +08:00
    有些人真是设计模式学傻了吧,问题的关键在于“优化 if 提升性能”这个错误认知吧
    NeroKamin
        41
    NeroKamin  
       2022-11-08 10:06:20 +08:00
    可以优化代码,但是对于性能上优化可能不太会有帮助
    mingsz
        42
    mingsz  
       2022-11-08 10:43:02 +08:00
    不动,继续加 if
    万一重构后,部分逻辑与之前不一样就 gg
    6david9
        43
    6david9  
       2022-11-08 10:47:41 +08:00 via iPhone
    看下响应链模式是否满足你的需求
    fgwmlhdkkkw
        44
    fgwmlhdkkkw  
       2022-11-08 10:52:14 +08:00
    每个模板需要的参数和值是确定的,那就可以查表呀。

    "a:a1,b:b1..." : tpl1
    "a:a2,b:b1..." : tpl2
    leonshaw
        45
    leonshaw  
       2022-11-08 10:55:05 +08:00
    判断这块需要优化的依据是什么?
    MYli001
        46
    MYli001  
       2022-11-08 10:57:11 +08:00
    放 map 里面最简单
    fgwmlhdkkkw
        47
    fgwmlhdkkkw  
       2022-11-08 10:57:25 +08:00
    @fgwmlhdkkkw #44
    如果值不是确定的,那可以 `({fn: (params: Params) => bool, hits: number})[]`依次执行,找到 hits 加一,一段时间后按照 hits 降序,理论上也会提高性能。
    fgwmlhdkkkw
        48
    fgwmlhdkkkw  
       2022-11-08 10:58:20 +08:00
    但是你要让我改,我肯定不想改……
    kingbill
        49
    kingbill  
       2022-11-08 11:10:55 +08:00
    提升性能的话,是打算并发判断吗?好像也不是不行,但总感觉没有必要
    jsjjdzg
        50
    jsjjdzg  
       2022-11-08 11:13:23 +08:00
    各种规则引擎下来还是 if 最快,把常用的 if 条件放前面就是最好的
    HugoChao
        51
    HugoChao  
       2022-11-08 11:20:33 +08:00
    才一百个,没有性能问题吧。保持这个结构,方便以后继续改逻辑
    7911364440
        52
    7911364440  
       2022-11-08 11:36:19 +08:00
    txy3000
        53
    txy3000  
       2022-11-08 11:39:06 +08:00
    做个 profile 再来谈性能 你确定瓶颈是 if 太多?
    shanghai1943
        54
    shanghai1943  
       2022-11-08 11:57:45 +08:00   ❤️ 1
    假如你为了所谓的命中率高的放前面,移动了 if 的逻辑判断顺序,会不会导致某些业务逻辑的执行顺序发生变化了。

    假设存在两种传参 a=1,b=2 和 a=1,b=2,c=3 ,以及两种 if 判断 a=1&&b=2 和 a=1&&c=3 ,如果调整了 if 的判断顺序,可能执行的业务就变得不一样了。

    建议慎重。。
    HanMeiM
        55
    HanMeiM  
       2022-11-08 12:24:13 +08:00
    用 map 做 key -> function 的驱动注册
    hhjswf
        56
    hhjswf  
       2022-11-08 12:27:04 +08:00
    if else 能有什么性能问题无非是丑了点
    cyrbuzz
        57
    cyrbuzz  
       2022-11-08 12:53:26 +08:00
    每个判断写成一个函数?对应的返回值可以写成枚举,1,2,3,4 这样,然后枚举和模板对应起来。

    js 代码:

    ```
    const enmu = {
    1: '模板 1',
    ....
    }

    const judgeFunc = [() => { return false }, () => { return true }]


    const finded = judgeFunc.findIndex((func) => { return func() })

    // 加判断
    enmu[finded]()
    ```

    随便扩展 enmu 和 judgeFunc 就可以了。
    bk201
        58
    bk201  
       2022-11-08 13:05:17 +08:00
    优化的目的是啥?增强可读性还是要做扩展?老系统能用就不要优化。你要优化,那还是那句话,首先优化的目标是啥?
    Ashore
        59
    Ashore  
       2022-11-08 13:12:25 +08:00
    改出问题你负责?不要想着去优化这个优化那个,业务能跑才是最重要的。
    vacuitym
        60
    vacuitym  
       2022-11-08 13:16:11 +08:00
    如果是为了程序可读性,而且每个变量对应的判断只有一种,可以对每个变量做一次真假的判断,然后存到一个 100 位的二进制中,然后对 100 个模版进行二进制的对应
    yolee599
        61
    yolee599  
       2022-11-08 13:20:42 +08:00 via Android
    建表,把所有需要判断的条件做成列,所有的处理函数作为行。一行一行遍历,每一行遍历所有列,如果有空列,则不做这列的判断,有符合条件的行就执行该行的处理函数。这样看起来比较好看,就是会损失一点点性能
    ipwx
        62
    ipwx  
       2022-11-08 13:40:26 +08:00
    楼上已经提到过了,用统计重新排列 if 的顺序可以提速。更近一步,可以通过命中概率构建一个二叉树,类似于霍夫曼树。然后自动生成嵌套的 if 代码。这样速度是最快的。

    https://zhuanlan.zhihu.com/p/54714101
    xlzyxxn
        63
    xlzyxxn  
       2022-11-08 13:52:35 +08:00
    无非丑了点,不要嘲笑别人,也不要怕被别人嘲笑,switch 表结构和 if 条件分支预测是能快,但优雅的代码是建立在解决业务问题之上的,不那么优雅的代码往往是因为复杂的业务问题。
    weixiangzhe
        64
    weixiangzhe  
       2022-11-08 13:59:21 +08:00
    我也觉得拆成 责任链 比较好
    forbreak
        65
    forbreak  
       2022-11-08 14:18:00 +08:00
    如果是为了性能那么就不用优化了。 提升性能觉对不会需要你再去优化这个 if 的性能。 因为肯定有比这个地方更慢的东西值得你去优化。要是为了优化代码结构还值得去折腾折腾。
    PythonYXY
        66
    PythonYXY  
       2022-11-08 14:21:02 +08:00
    别重构了,到时候屎山崩了你要负责的
    GLee9507
        67
    GLee9507  
       2022-11-08 14:22:54 +08:00
    责任链模式+1
    @weixiangzhe
    BQsummer
        68
    BQsummer  
       2022-11-08 14:25:52 +08:00
    这种场景 if 是最快的了
    TArysiyehua
        69
    TArysiyehua  
       2022-11-08 14:26:41 +08:00
    100 个 if 完全没必要优化,效率贼高,上面说的提高命中率和加设计模式能提高你写代码的技术,这个倒是真的。但是对性能是几乎没有帮助的。
    WhiteDragon96
        70
    WhiteDragon96  
       2022-11-08 14:28:10 +08:00
    把所有对应关系放 map 里面
    xuelu520
        71
    xuelu520  
       2022-11-08 14:38:05 +08:00
    这种真没办法,必须这么多 if 每个来处理,顶多按#9 楼的说法,高频放上面。
    kaf
        72
    kaf  
       2022-11-08 15:14:03 +08:00
    写一百个枚举或者 key-value 放 map 里
    XXWHCA
        73
    XXWHCA  
       2022-11-08 16:21:24 +08:00
    判断规则都不一样,这个是没办法改,上面说用 map ,枚举的都没有好好审题,#9 才是最实际的,高频放上面
    ScepterZ
        74
    ScepterZ  
       2022-11-08 16:27:28 +08:00
    你这个是有优先级的,不能直接改顺序,才 100 个 if 没啥好优化的,不差这点性能
    你要是优化代码结构还可以搞一下
    lazyfighter
        75
    lazyfighter  
       2022-11-08 16:28:40 +08:00
    所有的优化都是由繁化简,楼主首要前提是理解这 30 多个参数的含义,以及他们是怎么组合的,if 能有什么性能问题?
    newmlp
        76
    newmlp  
       2022-11-08 16:48:08 +08:00
    为啥要优化,100 个 if 构不成性能问题吧
    v2eb
        77
    v2eb  
       2022-11-08 18:48:03 +08:00 via Android
    性能应该不成问题。
    主要代码长, 逻辑难梳理, 所以问题应该是:
    如何以可读性更高的方式优化 100 个 if 嵌套?
    winglight2016
        78
    winglight2016  
       2022-11-08 18:54:53 +08:00
    用 switch 吧,onehotencode 编码一下就可以了
    yinft
        79
    yinft  
       2022-11-08 19:31:35 +08:00
    第一反应是放 map 做映射
    xuanbg
        80
    xuanbg  
       2022-11-09 08:07:05 +08:00
    这么多条件,唯有查表解君愁。
    mg52033
        81
    mg52033  
       2022-11-09 09:01:36 +08:00
    100 个 if else 性能最高
    fenglangjuxu
        82
    fenglangjuxu  
       2022-11-09 12:56:51 +08:00 via iPhone
    Drools
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2735 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 00:29 · PVG 08:29 · LAX 16:29 · JFK 19:29
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.