MIT6.824中 MapReduce 的示例 mrsequential.go

85 阅读2分钟

MIT6.824中 MapReduce 的示例 mrsequential.go

任务

mrsequential.go 这是一个同步代码,也就是说一个进程就完成了整个计算任务。

首先要明确 MapReduce 的目标是计算出各个单词一共出现了多少次。

代码思路

指明数据文件和功能函数:

首先呢,数据来源于项目中的文件,所以需要将文件传入给程序:

go run -race mrsequential.go wc.so pg*.txt

上述命令中包含了两个参数:一个是 pg*.txt ,这个指定的就是数据文件(待会就是要统计这里面的各个单词的出现次数);至于另一个参数wc.so,这个可以理解为一个集成插件吧(主要是为我们提供 map 函数和 reduce 函数的具体实现的)

// os.Args[1] 就是 wc.so
// 经过这一步,可以得到对应的 map 函数和 reduce 函数
mapf, reducef := loadPlugin(os.Args[1])

Map任务: 在这之前已经完成了所有基本工作的准备了,所以这里会正式进行数据统计。

  1. 遍历各个数据文件,获取文件内容
  2. 将内容作为入参传给 map 函数
  3. map 函数处理得到,形如[{A,1},{A,1}{b,1}]
kva := mapf(filename, string(content))

排序: 这一步是位于 Map 和 Reduce 中间的步骤,它所做的工作就是将 map 函数返回的结果根据 key 排序;这样做主要的目的就是为了方便后序 Reduce 阶段的统计

sort.Sort(ByKey(intermediate))

Reduce 任务: 这个阶段的任务就是要将 [{A,1},{A,1}{b,1}] 变成 [{A,2},{b,1}]

下面我们来看看它的具体做法:

  1. 将 map 返回的结果 [{A,1},{A,1}{b,1}] ,变成 [A,A,b]
  2. 将 [A,A,b] 交给 reduce 函数处理,得到 A:2, b:1
  3. 将 A:2, b:1 写入文件
	i := 0
	// intermediate [{"key","value"},{"key", "value"}]
	for i < len(intermediate) {
		j := i + 1
		// 找到所有相同 key 的键值对
		for j < len(intermediate) && intermediate[j].Key == intermediate[i].Key {
			j++
		}
		values := []string{}
		for k := i; k < j; k++ {
			// values ["value","value"]
			values = append(values, intermediate[k].Value)
		}

		// 统计出 key 对应的个数有多少个
		output := reducef(intermediate[i].Key, values)

		// this is the correct format for each line of Reduce output.
		fmt.Fprintf(ofile, "%v %v\n", intermediate[i].Key, output)

		i = j
	}