当前位置: 首页 > 知识库问答 >
问题:

如何提高图中心度计算的并行性能?

夏侯弘量
2023-03-14

我得到的性能下降后,并行化的代码,计算图中心。图比较大,100K顶点。单线程应用程序大约需要7分钟。根据julialang站点(http://julia.readthedocs.org/en/latest/manual/parallel-computing/#man-parallel-computing)的建议,我修改了代码并使用pmap api来并行计算。我开始计算8个过程(julia-p 8calc_centrality.jl)。令我惊讶的是,我慢了10倍。并行过程现在需要一个多小时。我注意到并行进程初始化和开始计算需要几分钟。即使在所有8 html" target="_blank">CPU是0忙于julia应用程序,计算是超级慢。

任何关于如何提高并行性能的建议都将不胜感激。

calc_centrality.jl:

using Graphs
require("read_graph.jl")
require("centrality_mean.jl")

function main()
    file_name = "test_graph.csv"
    println("graph creation: ", file_name)
    g = create_generic_graph_from_file(file_name)
    println("num edges: ", num_edges(g))
    println("num vertices: ", num_vertices(g))

    data = cell(8)
    data[1] = {g, 1, 2500}
    data[2] = {g, 2501, 5000}
    data[3] = {g, 5001, 7500}
    data[4] = {g, 7501, 10000}
    data[5] = {g, 10001, 12500}
    data[6] = {g, 12501, 15000}
    data[7] = {g, 15001, 17500}
    data[8] = {g, 17501, 20000}
    cm = pmap(centrality_mean, data)
    println(cm)

end
println("Elapsed: ", @elapsed main(), "\n")

你的意思是中心性。jl

using Graphs

function centrality_mean(gr, start_vertex)
    centrality_cnt = Dict()
    vertex_to_visit = Set()
    push!(vertex_to_visit, start_vertex)

    cnt = 0
    while !isempty(vertex_to_visit)
        next_vertex_set = Set()
        for vertex in vertex_to_visit
            if !haskey(centrality_cnt, vertex)
                centrality_cnt[vertex] = cnt
                for neigh in out_neighbors(vertex, gr)
                    push!(next_vertex_set, neigh)
                end
            end
        end
        cnt += 1
        vertex_to_visit = next_vertex_set
    end
    mean([ v for (k,v) in centrality_cnt ])
end

function centrality_mean(data::Array{})
    gr = data[1]
    v_start = data[2]
    v_end = data[3]
    n = v_end - v_start + 1;
    cm = Array(Float64, n)
    v = vertices(gr)
    cnt = 0
    for i = v_start:v_end
        cnt += 1
        if cnt%10 == 0
            println(cnt)
        end
        cm[cnt] = centrality_mean(gr, v[i])
    end
    return cm
end

共有3个答案

吕俊才
2023-03-14

从Julia关于并行计算的页面:

Julia提供了一个基于消息传递的多处理环境,允许程序同时在不同内存域中的多个进程上运行。

如果我正确地解释这一点,Julia的并行性需要消息传递来同步进程。如果每个单独的进程只做很少的工作,然后进行消息传递,那么计算将被消息传递开销所主导,而不做任何工作。

我从你的代码中看不到,我也不太了解朱莉娅,看不到并行中断在哪里。但是你有一个很大的复杂的图,它可以随意地分布在多个过程中。如果他们需要在跨图链接时进行交互,你就会有这样的开销。

您可以通过将图的分区预先计算成大小大致相等、高度内聚的区域来修复它。我怀疑分手需要你已经想做的那种复杂的图形处理,所以你可能有一个鸡和蛋的问题要启动。

可能是朱莉娅给你提供了错误的并行模型。您可能需要一个共享地址空间,这样在图中行走的线程就不必使用消息来遍历弧。

梁德馨
2023-03-14

下面是作者在评论中建议的带有@everywhere的代码https://stackoverflow.com/users/1409374/rickhg12hs.解决了性能问题!!!

test_parallel_pmap.jl

using Graphs
require("read_graph.jl")
require("centrality_mean.jl")

function main()
   @everywhere file_name = "test_data.csv"
   println("graph creation from: ", file_name)
   @everywhere data_graph = create_generic_graph_from_file(file_name)
   @everywhere data_graph_vertex = vertices(data_graph)
   println("num edges: ", num_edges(data_graph))
   println("num vertices: ", num_vertices(data_graph))

   range = cell(2)
   range[1] = {1, 25000}
   range[2] = {25001, 50000}
   cm = pmap(centrality_mean_pmap, range)
   for i = 1:length(cm)
       println(length(cm[i]))
  end
end

println("Elapsed: ", @elapsed main(), "\n")

你的意思是中心性。jl

using Graphs

function centrality_mean(start_vertex::ExVertex)
    centrality_cnt = Dict{ExVertex, Int64}()
    vertex_to_visit = Set{ExVertex}()
    push!(vertex_to_visit, start_vertex)

    cnt = 0
    while !isempty(vertex_to_visit)
        next_vertex_set = Set()
        for vertex in vertex_to_visit
            if !haskey(centrality_cnt, vertex)
                centrality_cnt[vertex] = cnt
                for neigh in out_neighbors(vertex, data_graph)
                    push!(next_vertex_set, neigh)
                end
            end
        end
       cnt += 1
       vertex_to_visit = next_vertex_set
    end
    mean([ v for (k,v) in centrality_cnt ])
end

function centrality_mean(v_start::Int64, v_end::Int64)
    n = v_end - v_start + 1;
    cm = Array(Float64, n)
    cnt = 0
    for i = v_start:v_end
        cnt += 1
        cm[cnt] = centrality_mean(data_graph_vertex[i])
    end
    return cm
end

function centrality_mean_pmap(range::Array{})
    v_start = range[1]
    v_end = range[2]
    centrality_mean(v_start, v_end)
end
陈文景
2023-03-14

我猜这和平行无关。您的第二个centrality_mean方法不知道什么类型的对象grv_startv_end。所以它将不得不为那个“外环”使用非优化的、缓慢的代码

虽然有几种可能的解决方案,但最简单的方法可能是分解从pmap接收“命令”的函数:

function centrality_mean(data::Array{})
    gr = data[1]
    v_start = data[2]
    v_end = data[3]
    centrality_mean(gr, v_start, v_end)
end

function centrality_mean(gr, v_start, v_end)
    n = v_end - v_start + 1;
    cm = Array(Float64, n)
    v = vertices(gr)
    cnt = 0
    for i = v_start:v_end
        cnt += 1
        if cnt%10 == 0
            println(cnt)
        end
        cm[cnt] = centrality_mean(gr, v[i])
    end
    return cm
end

所有这些只是创建了一个中断,并给julia一个机会来优化第二部分(包含性能关键循环)的实际输入类型。

 类似资料:
  • 投的上海的高性能计算被挂了,被北京的高性能计算的语音技术部捞了 百度面试官非常好,体验感非常棒,奈何自己太菜了,全程道歉 一面 8.2 项目深挖 算子开发相关涉及知识点 GPU架构,内存模型 并发编程 锁 信号量 创建线程的几种方式 lambda表达式的底层是怎么实现的 std::move 使用场景,他比赋值构造好在哪 lock_guard相比较于lock/unlock能防止什么问题? cuda

  • 问题内容: 我正在通过XML数据生成pdf文件。 我将段落元素的高度计算为: 但是这种方法不能正常工作。 你能给我个主意吗? 问题答案: 您的问题很奇怪。根据您的问题的标题,您想知道字符串的高度,但是您的代码显示您要求的是字符串的宽度。 请看一下FoobarFilmFestival示例。 如果是实例,则可以使用: 当我们使用12号字体时,这将返回基线以上的高度和基线以下的高度。您可能知道,字体大小

  • 我有一个简单的任务:确定需要多少字节来将某个数字(字节数组长度)编码到字节数组并编码最终值(实现本文:编码长度和值字节)。 最初我写了一个快速完成任务的方法: 这是一段旧代码,编写方式很糟糕。 现在我正在尝试使用按位运算符或类来优化代码。这是按位版本的示例: 以及类的最终实现: 所有方法都按预期工作。我使用秒表类页面中的一个示例来衡量性能。性能测试让我惊讶。我的测试方法执行了1000次该方法的运行

  • 我有一个包含一个。我想调整文本视图的大小,以便在给定固定宽度的情况下,显示整个字符串而不滚动。 有一个方法,允许为给定大小计算其边框 但不幸的是,它似乎不起作用,因为它总是返回单行的高度。

  • 我正在研究一个基于代理的流行病模型。这个想法是单个代理根据他们在网络中观察到的情况(基于距离)做出决定。我在每个代理中都有几个功能,可以动态更新受感染接触者的数量,接触者表现出特定行为等。 下面的代码用于计算代理网络中受感染的联系人。 至少还有3个这样的函数可以保持表示代理网络中其他功能的其他代理的计数。现在,当我 有没有一种计算效率更高的方法来跟踪更大人口的网络统计数据?

  • 我必须制作一个程序来找到显示n的最大方式!数字(不包括1)。 比如:4!= 1x2x3x4 = 1x2x3x2x2。所以你可以用5个数的乘积来表示4!。所以输入是4,输出是5。5是你能表达4的最大数量!。 简单地说,就是将一个阶乘数分解为素因子,计算出它们的个数并显示出来。 我所做的是一个“for”循环,在这个循环中我计算1到“n”的所有素因子及其数量。 但我对大数字有一个问题,比如当“n”是10