【问题标题】:Looking for advice on improving a custom function in AnyLogic寻找有关改进 AnyLogic 中的自定义功能的建议
【发布时间】:2021-09-12 00:16:21
【问题描述】:

我正在使用旁路距离估算大型城市网络中的最后一英里交付成本。我有超过 8000 名客户代理和 100 多名零售店代理使用纬度/经度坐标绘制在 GIS 地图中。每个客户从最近的商店(按路线)接收交货。目标是在此网络中为每个商店获取两个距离度量:

d0_bar:从商店到所有指定客户的平均距离
d1_bar:单个商店共有的所有客户之间的平均距离

我编写了一个带有简单 foreach 循环的启动函数,以根据路径距离将每个客户分配到一个商店(客户有一个参数,“customer.pStore”,属于 Store 类型)。该函数还依次将每个客户添加到商店代理的客户集合中(“store.colCusts”;它是一个包含客户类型元素的数组列表)。

接下来,我有一个函数,它遍历商店代理人口并计算上面的两个平均距离测量值(d0_bar 和 d1_bar)并将结果写入 txt 文件(参见下面的代码)。幸运的是,该代码有效。然而,问题在于,对于如此庞大的数据集,遍历所有客户/商店并通过 openstreetmap.org API 检索距离的过程需要永远。它已经初始化(“请稍候...”)大约 12 小时。我该怎么做才能使这段代码更有效率?或者,在 AnyLogic 中是否有更好的方法来为我的网络中的每个商店获取这两个距离度量?

提前致谢。

    //for each store, record all customers assigned to it
    for (Store store : stores) 
        {
        distancesStore.print(store.storeCode + "," + store.colCusts.size() + "," + store.colCusts.size()*(store.colCusts.size()-1)/2 + ",");
    
    //calculates average distance from store j to customer nodes that belong to store j
        double sumFirstDistByStore = 0.0;
        int h = 0;
        while (h < store.colCusts.size())
            {
            sumFirstDistByStore += store.distanceByRoute(store.colCusts.get(h));
            h++;
            }
        distancesStore.print((sumFirstDistByStore/store.colCusts.size())/1609.34 + ",");
            
    //calculates average of distances between all customer nodes belonging to store j
        double custDistSumPerStore = 0.0;
        int loopLimit = store.colCusts.size();
        int i = 0;
        while (i < loopLimit - 1)
            {
            int j = 1;
            while (j < loopLimit)
                {
                custDistSumPerStore += store.colCusts.get(i).distanceByRoute(store.colCusts.get(j));
                j++;
                }
            i++;
            }   
        distancesStore.print((custDistSumPerStore/(loopLimit*(loopLimit-1)/2))/1609.34);
        distancesStore.println();
        }

【问题讨论】:

    标签: anylogic


    【解决方案1】:

    首先是几个简单的 cmets:

    1. 您是否尝试过为单个distanceByRoute 呼叫计时?例如。您可以尝试运行store.distanceByRoute(store.colCusts.get(0)); 来查看单个呼叫在您的系统上占用多长时间。路由通常很慢,但最好知道限速是多少。
    2. 第一个简单的更改是使用 java 并行性。而不是使用这个:
        for (Store store : stores)
        { ...
    

    使用这个:

        stores.parallelStream().forEach(store -> {
        ...
        });
    

    这将使用 standard Java streams API 并行处理 stores 条目。

    1. 看起来也像第二个循环 - 计算客户之间的平均距离时没有考虑镜像。也就是说距离a->b等于b->a。因此,例如,4 个客户将需要 6 次计算:1->2、1->3、1->4、2->3、2->4、3->4。而如果有 4 个客户,您的第二个 while 循环将执行 9 次计算: i=0, j in {1,2,3}; i=1, j in {1,2,3}; i=2, j in {1,2,3},这似乎是错误的,除非我误解了你的意图。
    2. 通常,对于长时间运行的操作,最好包含一些 traceln 以显示相关时间的进度。

    请查看上面并发布结果。有了更多信息,可能会进一步提高性能。

    【讨论】:

    • 谢谢。 1) 我只用一小部分数据编写和测试了代码(2 个商店,16 个客户)。当我运行模型时,初始化时间几乎不明显(可能不到一秒钟,但我没有检查控制台)。 2)这很有趣。我会更多地研究这个。 3)你是对的,有一个错误。应该是 int j = i+1。我假设一个无向网络,所以 a->b 应该与 b->a 相同。 4) 好建议。谢谢。
    • 还要补充一点:可以通过向 JVM 添加更多内存来实现加速(将减少 GC 暂停)
    • 接下来,parallelStream() 与在运行时首选项下设置要使用的处理器数量有何不同?此外,我模型中的商店代理不是一个集合,而是一个总体。看起来 parallelStream() 必须在集合上完成;我理解的对吗?
    • parallelSteams() 是 Java 功能,使用的处理器数量仅指多次运行实验。是的,parallelStreams() 仅适用于集合,但没有什么能阻止您将 Store 代理放入集合中,它们可以从多个地方(即人口和集合)引用。
    猜你喜欢
    • 2013-06-27
    • 2011-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-05
    • 1970-01-01
    • 2021-06-12
    • 2013-02-01
    相关资源
    最近更新 更多