Golang Dijkstra goroutines(戈兰语 Dijkstra 协程)

huangapple go评论98阅读模式
英文:

Golang Dijkstra goroutines

问题

所以基本上我需要使用goroutines来编写一个Dijkstra程序。

我已经基本完成了所有工作,只是在goroutines方面有一点问题。由于这是一个Dijkstra算法,我正在使用一个函数来找到从给定节点到所有其他节点的最短路径。正如您在下面的代码中所看到的,goroutine必须帮助我找到从n到n个节点的最短路径。

//此函数将为我们提供从所有节点到所有其他节点的所有最短路径
//list []Edge是包含由.txt文件给出的所有特征的列表
//nodes []int给出了我们图中的所有节点
//map[int]map[int][]int是所有路径的结果,例如{1:{2:1 2 3:[1 3]...} 2:{1:{2 1}...}...}
//map[int]map[int]int是不同路径的所有距离,例如{1:{2:1 3:2 4:3...},2...}
func Dijkstra(list []Edge, nodes []int) (map[int]map[int][]int, map[int]map[int]int) {
var wg sync.WaitGroup // WaitGroup,以便在所有goroutine完成之前不会有一些事情完成
dijk := make(map[int]map[int][]int)
distance := make(map[int]map[int]int)
//start := time.Now()
neighbors := getAllNeighbors(list, nodes)
//fmt.Print(neighbors)
//我们为我们图中的每个节点获取所有邻居
//{1:[{1 2 1},{1 3 2}],B:...}
for _, node := range nodes { //对于我们拥有的每个节点,我们将获取到所有其他节点的最短路径
var routes map[int][]int
var distances map[int]int

    wg.Add(1)   //我们在等待组中添加下一个goroutine
    go func() { //goroutine
        routes, distances = oneDijkstra(node, &wg, list, nodes, neighbors) //函数将为我们提供从节点到列表的其他节点的最短路径
    }()
    wg.Wait() //我们等待直到等待组为空,然后执行其余的代码
    //如果routes没有完成,我们不能将其添加到dijk中
    dijk[node] = routes
    //对于此节点,我们添加其他节点以及与它们具有最短路径的方式
    distance[node] = distances
    //对于此节点,我们为每个其他节点添加最短路径所需的成本
}
//fmt.Print(time.Since(start))
return dijk, distance

}

问题在于,这段代码在其当前状态下没有很好地使用goroutines。我想知道应该在哪里放置它,以使我的结果更快(因为在这里,就好像没有goroutines)。提前感谢任何能够给我提供一些解决方案的人。

英文:

So basically I need to do a Dijkstra program using goroutines.

I've done basically everything except I have a little problem with the goroutines. Since it's a Dijkstra algorithm, I'm using a function to find the shortest path from a given node to all the others. The goroutine must help me to find the shortest path from n to n nodes as you can see in the code below.

//This function will get us all the shortest paths from all the nodes to all the other nodes
//list []Edge here is our list containing all the characteristics given by the .txt file
//nodes []int gives us all the nodes in our graph
//map[int]map[int][]int is all the results for the paths for e.g {1:{2:[1 2](the paths that it took) 3:[1 3]...} 2:{1:{2 1}...}...}
//map[int]map[int]int is all the distances for the different paths for e.g {1:{2:1 3:2 4:3...},2...}
func Dijkstra(list []Edge, nodes []int) (map[int]map[int][]int, map[int]map[int]int) {
	var wg sync.WaitGroup // Waitgroup so that we won't get some things done before all the goroutines are done
	dijk := make(map[int]map[int][]int)
	distance := make(map[int]map[int]int)
	//start := time.Now()
	neighbors := getAllNeighbors(list, nodes)
	//fmt.Print(neighbors)
	//We get all the neighbors for every node we have in our graph
	//{1:[{1 2 1},{1 3 2}],B:...}
	for _, node := range nodes { //for every node we have we are going to get the shortest path to all the other nodes
		var routes map[int][]int
		var distances map[int]int

		wg.Add(1)   //We add our next goroutine in the waitgroup
		go func() { //goroutine
			routes, distances = oneDijkstra(node, &wg, list, nodes, neighbors) //function that will give us the shortes path from the node to other nodes of the list
		}()
		wg.Wait() //We wait until the waitgroup is empty to do the rest of the code
		//We can't add routes to our dijk if it's not completed
		dijk[node] = routes
		//for this node, we add the other nodes with the way to take to have the shortest path with them
		distance[node] = distances
		//for this node, we add for every other node the cost it takes for the shortest path
	}
	//fmt.Print(time.Since(start))
	return dijk, distance
}

The problem is that this code in its actual state doesn't use well the goroutines. I would like to know where should I put it to make my results much faster(since here it's like there are no goroutines). Thank you in advance to any one who may be able to give me some solutions.

答案1

得分: 3

你的Dijkstra函数无法并发处理节点的主要原因是你在循环中等待goroutine完成(使用wg.Wait())。实质上,每个节点都没有被并发处理。

一个潜在的解决方案是:

首先,修改你的oneDijkstra函数,使其接收一个通道,你可以将数据发送到该通道(数据只是包含所有信息的结构体)。

func oneDijkstra(node int, wg *sync.WaitGroup, list []Edge, nodes []int, neighbors []Edge, dataCh chan<- data) {
   defer wg.Done()
   //你的计算
   // ...
   dataCh <- data{node, routes, distances}
}

接下来,在Dijkstra函数中,你需要做一些改变。

首先,启动一个goroutine来从dataCh通道读取数据并添加到映射中。我个人更喜欢这个解决方案,因为它避免了并发修改映射的问题。

然后,遍历节点,在循环后等待所有操作完成。

func Dijkstra(list []Edge, nodes []int) (map[int]map[int][]int, map[int]map[int]int) {
    var wg sync.WaitGroup
    dataCh := make(chan data)
    done := make(chan bool)
    dijk := make(map[int]map[int][]int)
    distance := make(map[int]map[int]int)
    neighbors := getAllNeighbors(list, nodes)

    //启动一个goroutine来从dataCh通道读取数据
    go func() {
        for d := range dataCh {
            dijk[d.node] = d.routes
            distance[d.node] = d.distances
        }
        done <- true //这用于等待直到所有数据都从通道中读取完毕
    }()

    wg.Add(len(nodes))
    for _, node := range nodes {
        go oneDijkstra(node, &wg, list, nodes, neighbors, dataCh)
    }

    wg.Wait()
    close(dataCh) //关闭dataCh通道,一旦所有数据都被读取,for-range循环就会退出
    <-done //等待所有数据被读取并放入映射中

    return dijk, distance
}
英文:

The main reason why your Dijkstra function is not processing nodes concurrently is because you wait for the goroutine to finish within the loop (with wg.Wait()). Essentially, each node is not concurrently processed.

One potential solution:

First, modify your oneDijkstra function to receive a channel to which you would send the data (data is just your struct that contains all of the info).

func ondeDijkstra(node int, wg *sync.WaitGroup, list []Edge, nodes []int, neighbours []Edge, dataCh chan&lt;- data){
   defer wg.Done()
   //your calculations
   // ...
   datach &lt;- data{node, routes, distances}
}

Next, in the Dijkstra function, you will need to change a couple of things.

First, start a goroutine that will read from the dataCh channel and add to the maps. I personally prefer this solution since it avoids maps being modified concurrently.
Next, go through the nodes, start a goroutine for each and wait for everything to finish after the loop.

func Dijkstra(list []Edge, nodes []int) (map[int]map[int][]int, map[int]map[int]int) {
    var wg sync.WaitGroup 
    datach := make(chan data)
    done := make(chan bool)
    dijk := make(map[int]map[int][]int)
    distance := make(map[int]map[int]int)
    neighbors := getAllNeighbors(list, nodes)

    //start a goroutine that will read from the data channel
    go func(){
      for d := range dataCh {
        dijk[d.node] = d.routes
        distance[d.node] = d.distances
      }
      done &lt;- true //this is used to wait until all data has been read from the channel
    }()
    
    wg.Add(len(nodes))
    for _, node := range nodes {  
        go oneDijkstra(node, &amp;wg, list, nodes, neighbors, dataCh)
    }
    
    wg.Wait()
    close(dataCh) //this closes the dataCh channel, which will make the for-range loop exit once all the data has been read
    &lt;- done //we wait for all of the data to get read and put into maps

    return dijk, distance
}

答案2

得分: 0

我认为将等待移动到for循环之后,并直接将结果分配给切片,可以实现你想要的效果。

for _, node := range nodes { // 对于我们拥有的每个节点,我们将获取到所有其他节点的最短路径
    wg.Add(1)   // 将下一个goroutine添加到等待组中
    go func() { // goroutine
       defer wg.Done();
       dijk[node], distance[node] = oneDijkstra(node, &wg, list, nodes, neighbors) // 函数将给出从节点到列表中其他节点的最短路径
    }()
}
wg.Wait();
英文:

I think moving your wait to after the for loop and assigning the results directly to your slices will do what you want.

for _, node := range nodes { //for every node we have we are going to get the shortest path to all the other nodes
        wg.Add(1)   //We add our next goroutine in the waitgroup
        go func() { //goroutine
           defer wg.Done();
           dijk[node] , distance[node] = oneDijkstra(node, &amp;wg, list, nodes, neighbors) //function that will give us the shortes path from the node to other nodes of the list
        }()
    }
    wg.wait();
    

huangapple
  • 本文由 发表于 2021年11月29日 22:23:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/70156258.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定