文章目录

  • 一.MapReduce简介
    • 1.1 MapReduce特点
      • 扩展性强
      • 使用起来比较简单
      • 高容错性
    • 1.2 MapReduce适用场景
  • 二.MapReduce工作原理(重要)
    • 2.1 MapReduce编程规范
      • Mapper
      • Reducer
      • Driver
    • 2.2 MapReduce程序执行过程中的两个主要步骤
    • 2.3 MapReduce的三类进程及其作用
    • 2.4 MapReduce程序工作流程分析(重要)
      • 2.4.1 MapReduce的数据切片机制及MapTask并行度
        • 数据切片与MapTask并行度并行度的关系
        • 数据块及数据切片
        • MapReduce的数据切片机制
          • 默认切片方式
          • 小文件数据切片方式
            • 虚拟存储过程:
            • 切片过程:
      • 2.4.2 MapReduce对输入数据文件的初步处理
        • TextInputFormat
        • KeyValueTextInputFormat
        • NLineInputFormat
        • 自定义InputFormat
      • 2.4.3 Map阶段
        • Read操作:
        • Map操作:
        • Collect操作:
        • Spill操作:
        • Combine操作:
      • 2.4.4 Reduce阶段
        • Copy操作:
        • Merge操作:
        • Sort操作:
        • Reduce操作:
      • 2.4.5 Shuffle机制
  • 三.MapReduce中的序列化
    • 3.1 Hadoop序列化特点
    • 3.2 Hadoop中使用序列化

一.MapReduce简介

MapReduce是一个分布式运算程序的编程框架,是用户开发基于Hadoop的数据分析应用的核心框架。MapReduce核心功能是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分布式运算程序,并行运行在一个Hadoop集群的所有节点上。

使用MapReduce框架实现一些接口,就可以完成一个分布式程序,这个分布式程序可以分布到大量廉价的PC机器上运行。也就是说写一个分布式程序,跟写一个简单的串行程序是一模一样的。就是因为这个特点使得MapReduce编程变得非常流行。当的计算资源不足时,可以通过简单的增加机器来扩展计算能力。MapReduce框架的出现解决了很多和算力不足有关的问题。

1.1 MapReduce特点

扩展性强

当计算资源不能得到满足的时候,可以通过简单的增加机器来扩展计算能力。

使用起来比较简单

使用MapReduce简单的实现一些接口,就可以完成一个分布式程序,和写一个简单的串行程序相比并没有复杂很多。就是因为这个特点使得MapReduce编程变得非常流行。

高容错性

MapReduce设计的初衷就是使程序能够部署在廉价的PC机器上,这就要求它具有很高的容错性。比如其中一台机器挂了,MapReduce可以把这台挂掉的机器上面的计算任务转移到另外一个节点上运行,不至于使整个任务运行失败,这个过程不需要人工参与,完全是由Hadoop内部完成的。

1.2 MapReduce适用场景

MapReduce擅长进行离线数据处理,即处理硬盘上静态的大规模数据。MapReduce不擅长实时计算,MapReduce无法像MySQL一样,在毫秒或者秒级内返回结果;MapReduce也不擅长流式计算,由于流式计算的输入数据是动态的,而MapReduce因为自身设计的原因,输入数据集必须是静态的,不能动态变化。MapReduce进行DAG(有向图)计算的效率也非常低,在多个应用程序存在依赖关系的场景下,后一个应用程序的输入为前一个的输出,使用MapReduce作业会进行大量的磁盘IO操作,导致性能非常的低下。

二.MapReduce工作原理(重要)

2.1 MapReduce编程规范

一个标准的MapReduce程序可以分成三个部分:Mapper、Reducer和Driver。

Mapper

用户自定义的Mapper要继承自己的父类
Mapper的输入数据是KV对的形式(KV的类型可自定义)
Mapper中的业务逻辑写在map()方法中
Mapper的输出数据是KV对的形式(KV的类型可自定义)
map()方法(MapTask进程)对每一个<K,V>调用一次

Reducer

用户自定义的Reducer要继承自己的父类
Reducer的输入数据类型对应Mapper的输出数据类型,也是KV
Reducer的业务逻辑写在reduce()方法中
ReduceTask进程对每一组相同k的<k,v>组调用一次reduce()方法

Driver

相当于YARN集群的客户端,用于提交整个程序到YARN集群,提交的是封装了MapReduce程序相关运行参数的job对象

2.2 MapReduce程序执行过程中的两个主要步骤

MapReduce运算程序可以分成两个比较大的步骤。第一步:MapTask并发实例,完全并行运行,对原始数据进行处理,输出<key,value>对格式的结果。第二步:ReduceTask使用上一个阶段的MapTask并发实例的输出,根据程序的逻辑再次进行一次处理。MapReduce编程模型只能包含一个Map阶段和一个Reduce阶段,如果用户的业务逻辑非常复杂,那就只能多个MapReduce程序,串行运行。

以经典的WordCount程序为例,其工作原理如下图所示,可以看出MapReduce程序分成了Map阶段和Reduce阶段两个步骤来进行处理。

2.3 MapReduce的三类进程及其作用

一个完整的MapReduce程序在分布式运行时有三类实例进程:

  1. MrAppMaster:负责整个程序的过程调度及状态协调。
  2. MapTask:负责Map阶段的整个数据处理流程。
  3. ReduceTask:负责Reduce阶段的整个数据处理流程。

2.4 MapReduce程序工作流程分析(重要)

下面来详细分析一下MapReduce程序的工作流程,下图是MapReduce程序的工作流程图。

  1. 确定待处理数据
  2. 客户端进行submit()操作前,会先获取待处理数据的信息,然后根据参数配置,形成一个任务分配的规划。
  3. 客户端提交切片信息给yarn
  4. 计算出maptask数量,并启动相应数量的maptask
  5. 从磁盘中读取数据
  6. 进行map阶段的逻辑运算
  7. 收集kv到缓存(缓存是是一个环形缓冲区)
  8. 按照分区排序后写入磁盘(如何进行分区可以自己指定)
  9. 所有maptask任务完成后,启动相应数量的reducetask,并告知reducetask处理数据范围(数据分区)
  10. reduce task获取数据,并进行reduce阶段的逻辑运算
  11. 输出结果到文件中

上述的几步操作分别由hadoop集群中不同的组件进行分工合作完成。1到3步由客户端负责,第4步由yarn负责,5到6步属于map阶段,7到8步处于map和reduce之间的阶段,这一过程中进行的处理被称为MapReduce的Shuffle机制,第9步由yarn负责,10到11步属于reduce阶段

在以上的流程中,有几个步骤需要重点分析:

  • 如何对原始数据进行切片并输入进集群,即MapReduce的切片机制
  • Map阶段的处理
  • Reduce阶段的处理
  • MapReduce的Shuffle机制

2.4.1 MapReduce的数据切片机制及MapTask并行度

数据切片与MapTask并行度并行度的关系

MapReduce的数据切片机制决定了MapTask的并行度,以不同的方式进行数据切片,MapReduce启动的MapTask进程数量也不同,MapTask的并行度的衡量指标就是MapTask进程数量。MapTask的并行度就是Map阶段的任务处理并发度,会影响到整个Job的处理速度。

MapTask的并行度对程序的运行速度影响很大。例如:1G的数据,启动8个MapTask,可以提高集群的并发处理能力。而1K的数据,也启动8个MapTask,则会让集群的效率大大降低。

所以如何对数据进行切片是非常重要的一个环节。

数据块及数据切片

数据块:也叫作Block,HDFS在物理上把数据分成一块一块,每一块就是一个Block数据块。
数据切片:也叫作split,数据切片只是在逻辑上对输入进行分片,并不会在磁盘上将其切分成片进行存储,数据切片是MapReduce中的概念。

MapReduce的数据切片机制

MapReduce常用的切片方式有两种,一种是默认情况下使用的切片方式,split切片大小默认等于Block的大小,按文件为单位切分;另一种是为了应对输入数据为大量小文件的场合。

默认切片方式

简单地按照文件的内容长度进行切片,split切片大小默认等于Block的大小,切片时不考虑数据集整体,而是逐个针对每一个文件单独切片。下面举一个例子说明:

输入数据有两个文件,file1.txt和file2.txt,file1.txt大小为300M,file2.txt大小为100M。经过切片机制运算后,形成的切片如下:

假设采用默认方式,以Block块大小作为切片大小,Block块默认大小为128M:
file1.txt.split1-- 0~128 大小为128M
file1.txt.split2-- 128~256M 大小为128M
file1.txt.split3-- 256~300M 大小为44M
file2.txt.split1-- 0~100M 大小为100M

假设采用自定义方式,设切片大小为100M:
file1.txt.split1-- 0~100 大小为100M
file1.txt.split2-- 100~200M 大小为100M
file1.txt.split3-- 200~300M 大小为100M
file2.txt.split1-- 0~100M 大小为100M

可以看出默认的切片机制的两个特点:

  • split切片大小默认等于Block的大小
  • 切片时逐个针对每一个文件单独切片
小文件数据切片方式

MapReduce框架默认的切片机制是对任务按文件规划切片,不管文件多小,只要文件大小小于block块的大小,都会被切成一个单独的切片,交给一个MapTask,这样如果有大量小文件,就会产生大量的MapTask,处理效率极其低下。

为了解决以上问题,应对小文件过多的场景,MapReduce还有一种切片方式,可以将多个小文件从逻辑上规划到一个切片中,这样,多个小文件就可以交给一个MapTask处理。这种方式生成切片的过程可以分为虚拟存储过程和切片过程二部分。

虚拟存储过程:

将输入目录下所有文件大小,依次和设置的切片最大值比较,如果不大于设置的最大值,逻辑上划分一个块。如果输入文件大于设置的最大值且大于两倍,那么以最大值切割一块;当剩余数据大小超过设置的最大值且不大于最大值2倍,此时将文件均分成2个虚拟存储块(防止出现太小切片)。

例如切片值为4M,输入文件大小为8.02M,则先逻辑上分成一个4M。剩余的大小为4.02M,如果按照4M逻辑划分,就会出现0.02M的小的虚拟存储文件,所以将剩余的4.02M文件切分成(2.01M和2.01M)两个文件。

切片过程:

判断虚拟存储的文件大小是否大于切片最大值,大于等于则单独形成一个切片。如果不大于设定的最大值则跟下一个虚拟存储文件进行合并,共同形成一个切片。

下面举一个例子说明:

有4个小文件大小分别为1.7M、5.1M、3.4M以及6.8M这四个小文件。
虚拟存储之后形成6个文件块,大小分别为:1.7M,(2.55M、2.55M),3.4M以及(3.4M、3.4M)
最终会形成3个切片,大小分别为:(1.7+2.55)M,(2.55+3.4)M,(3.4+3.4)M

2.4.2 MapReduce对输入数据文件的初步处理

MapReduce采用FileInputFormat类来对输入数据文件做初步处理。在运行MapReduce程序时,输入的文件格式包括:基于行的日志文件、二进制格式文件、数据库表等。针对不同的数据类型,MapReduce的FileInputFormat类实现了不同的接口,来处理不同类型的数据。FileInputFormat常见的接口实现类包括:TextInputFormat、KeyValueTextInputFormat、NLineInputFormat、CombineTextInputFormat和自定义InputFormat等。

TextInputFormat

TextInputFormat是默认的FileInputFormat实现类。按行读取每条记录。键是存储该行在整个文件中的起始字节偏移量, LongWritable类型。值是这行的内容,不包括任何行终止符(换行符和回车符),Text类型。下面举一个使用TextInputFormat的例子:

输入数据为:

Rich learning form
Intelligent learning engine
Learning more convenient
From the real demand for more close to the enterprise

经TextInputFormat处理后输出:

(0,Rich learning form)
(19,Intelligent learning engine)
(47,Learning more convenient)
(72,From the real demand for more close to the enterprise)

KeyValueTextInputFormat

每一行均为一条记录,被分隔符分割为key,value。可以通过在驱动类中设置conf.set(KeyValueLineRecordReader.KEY_VALUE_SEPERATOR, “\t”);来设定分隔符。默认分隔符是tab(\t)。下面举一个使用KeyValueTextInputFormat的例子,其中——>表示一个(水平方向的)制表符:

输入数据为:

line1 ——>Rich learning form
line2 ——>Intelligent learning engine
line3 ——>Learning more convenient
line4 ——>From the real demand for more close to the enterprise

经KeyValueTextInputFormat处理后输出:

(line1,Rich learning form)
(line2,Intelligent learning engine)
(line3,Learning more convenient)
(line4,From the real demand for more close to the enterprise)

NLineInputFormat

如果使用NlineInputFormat,代表每个map进程处理的InputSplit不再按Block块去划分,而是按NlineInputFormat指定的行数N来划分。即输入文件的总行数/N=切片数,如果不整除,切片数=商+1。下面举一个使用NLineInputFormat的例子:

如果N设为2,则每个输入分片包含两行。开启2个MapTask。

Rich learning form
Intelligent learning engine
Learning more convenient
From the real demand for more close to the enterprise

一个mapper负责处理:

(0,Rich learning form)
(19,Intelligent learning engine)

另一个mapper负责处理:

(47,Learning more convenient)
(72,From the real demand for more close to the enterprise)

NLineInputFormat生成的键和值与TextInputFormat生成的一样。

自定义InputFormat

在企业开发中,Hadoop框架自带的InputFormat类型不能满足所有应用场景,需要自定义InputFormat来解决实际问题。

实现一个自定义InputFormat需要三个步骤:

  1. 自定义一个类继承FileInputFormat。
  2. 改写RecordReader,实现一次读取一个完整文件封装为KV。
  3. 在输出时使用SequenceFileOutPutFormat输出合并文件。

2.4.3 Map阶段

上文曾提到,MapReduce程序运行时主要有三类实例进程在工作,分别是:MrAppMaster、MapTask、ReduceTask。Map阶段的各项工作均是由MapTask进程完成的,Map阶段又可以分为几个小的分操作。下图是Map阶段的操作流程图:

Read操作:

MapTask通过用户编写的RecordReader,从输入InputSplit中解析出一个个key/value。

Map操作:

该节点主要是将解析出的key/value交给用户编写map()函数处理,并产生一系列新的key/value。

Collect操作:

在用户编写map()函数中,当数据处理完成后,一般会调用OutputCollector.collect()输出结果。在该函数内部,它会将生成的key/value分区(调用Partitioner),并写入一个环形内存缓冲区中。

Spill操作:

即“溢写”,当环形缓冲区满后,MapReduce会将数据写到本地磁盘上,生成一个临时文件。需要注意的是,将数据写入本地磁盘之前,先要对数据进行一次本地排序,并在必要时对数据进行合并、压缩等操作。

溢写过程详细步骤:

步骤1:利用快速排序算法对缓存区内的数据进行排序,排序方式是,先按照分区编号Partition进行排序,然后按照key进行排序。这样,经过排序后,数据以分区为单位聚集在一起,且同一分区内所有数据按照key有序。

步骤2:按照分区编号由小到大依次将每个分区中的数据写入任务工作目录下的临时文件output/spillN.out(N表示当前溢写次数)中。如果用户设置了Combiner,则写入文件之前,对每个分区中的数据进行一次聚集操作。

步骤3:将分区数据的元信息写到内存索引数据结构SpillRecord中,其中每个分区的元信息包括在临时文件中的偏移量、压缩前数据大小和压缩后数据大小。如果当前内存索引大小超过1MB,则将内存索引写到文件output/spillN.out.index中。

Combine操作:

当所有数据处理完成后,MapTask对所有临时文件进行一次合并,以确保最终只会生成一个数据文件。当所有数据处理完后,MapTask会将所有临时文件合并成一个大文件,并保存到文件output/file.out中,同时生成相应的索引文件output/file.out.index。

在进行文件合并过程中,MapTask以分区为单位进行合并。对于某个分区,它将采用多轮递归合并的方式。每轮合并io.sort.factor(默认10)个文件,并将产生的文件重新加入待合并列表中,对文件排序后,重复以上过程,直到最终得到一个大文件。

每个MapTask最终只生成一个数据文件,可避免同时打开大量文件和同时读取大量小文件产生的随机读取带来的开销。

2.4.4 Reduce阶段

与Map阶段相同,Reduce阶段的各项工作均是由ReduceTask进程完成的,Reduce阶段也可以分为几个小的分操作。下图是Reduce阶段的操作流程图:

Copy操作:

ReduceTask从各个MapTask上远程拷贝一片数据,并针对某一片数据,如果其大小超过一定阈值,则写到磁盘上,否则直接放到内存中。

Merge操作:

在远程拷贝数据的同时,ReduceTask启动了两个后台线程对内存和磁盘上的文件进行合并,以防止内存使用过多或磁盘上文件过多。

Sort操作:

按照MapReduce语义,用户编写reduce()函数输入数据是按key进行聚集的一组数据。为了将key相同的数据聚在一起,Hadoop采用了基于排序的策略。由于各个MapTask已经实现对自己的处理结果进行了局部排序,因此,ReduceTask只需对所有数据进行一次归并排序即可。

Reduce操作:

reduce()函数将计算结果写到HDFS上。

2.4.5 Shuffle机制

Map阶段之后,Reduce阶段之前的数据处理过程称之为Shuffle。如下图所示:


下面的流程是整个MapReduce完整的工作流程,Shuffle过程是从第7步开始到第13步结束,具体Shuffle过程进行的操作如下:

  1. MapTask收集map()方法输出的kv对,放到内存缓冲区中
  2. 从内存缓冲区(环形)不断溢出本地磁盘文件,可能会溢出多个文件
  3. 多个溢出文件会被合并成大的溢出文件
  4. 在溢出过程及合并的过程中,都要调用Partitioner进行分区和针对key进行排序
  5. ReduceTask根据自己的分区号,去各个MapTask机器上取相应的结果分区数据
  6. ReduceTask会取到同一个分区的来自不同MapTask的结果文件,ReduceTask会将这些文件再进行合并(归并排序)
  7. 合并成大文件后,Shuffle的过程也就结束了,后面进入ReduceTask的逻辑运算过程(从文件中取出一个一个的键值对Group,调用用户自定义的reduce()方法)

Shuffle中的缓冲区大小会影响到MapReduce程序的执行效率,缓冲区越大,磁盘io的次数越少,执行速度就越快。缓冲区的大小可以通过参数io.sort.mb调整,默认设为100M。

三.MapReduce中的序列化

序列化就是把内存中的对象,转换成字节序列(或其他数据传输协议)以便于存储到磁盘(持久化)和网络传输。 反序列化将收到字节序列(或其他数据传输协议)或者是磁盘的持久化数据,转换成内存中的对象。

一般来说,对象只生存在内存里,关机断电就没有了。而且对象只能由本地的进程使用,不能被发送到网络上的另外一台计算机。 而通过序列化可以将内存中的对象存储到硬盘上,使对象能够被发送到远程计算机。

JDK本身就提供了序列化的功能,但是Java的序列化是一个重量级序列化框架(Serializable),一个对象被序列化后,会附带很多额外的信息(各种校验信息,Header,继承体系等),不便于在网络中高效传输。所以,Hadoop自己开发了一套序列化机制(Writable)。

3.1 Hadoop序列化特点

紧凑 :高效使用存储空间。
快速:读写数据的额外开销小。
可扩展:随着通信协议的升级而可升级
互操作:支持多语言的交互

3.2 Hadoop中使用序列化

Hadoop将一些常用的数据类型进行了序列化,方便在Hadoop框架中使用。常用的数据类型对应的Hadoop数据序列化类型:

Java类型 Hadoop Writable类型
Boolean BooleanWritable
Byte ByteWritable
Int IntWritable
Float FloatWritable
Long LongWritable
Double DoubleWritable
String Text
Map MapWritable
Array ArrayWritable

如果需要使用自定义的bean对象,即在Hadoop框架内部传递一个bean对象,那么该对象必需要实现序列化接口Writable。具体实现bean对象序列化需要注意一下7点:

1.实现Writable接口

2.反序列化时,需要反射调用空参构造函数,所以必须有空参构造

public FlowBean() {super();
}

3.重写序列化方法

@Override
public void write(DataOutput out) throws IOException {out.writeLong(upFlow);out.writeLong(downFlow);out.writeLong(sumFlow);
}

4.重写反序列化方法

@Override
public void readFields(DataInput in) throws IOException {upFlow = in.readLong();downFlow = in.readLong();sumFlow = in.readLong();
}

5.反序列化的顺序和序列化的顺序完全一致
6.要想把结果显示在文件中,需要重写toString(),可用”\t”分开,方便后续用。
7.如果需要将自定义的bean放在key中传输,则还需要实现Comparable接口,因为MapReduce框中的Shuffle过程要求对key必须能排序。

@Override
public int compareTo(FlowBean o) {
}

MapReduce计算框架知识总结(一)相关推荐

  1. Hadoop详解(六):MapReduce计算框架详解

    1. Hadoop MapReduce简介 Hadoop MapReduce是一个使用简便的软件框架,是Google云计算模型MapReduce的Java开源实现,基于它写出来的应用程序能够运行在由上 ...

  2. 大数据-MapReduce计算框架

    导语   MapReduce作为Hadoop核心编程模型,在Hadoop中,数据处理的核心就是MapReduce程序设计模型.下面就来分享一下MapReduce都有那些值得我们注意的事情. 文章目录 ...

  3. Twister: 迭代MapReduce计算框架

    摘要:MapReduce编程模型已经简化了许多数据并行应用的实现.编程模型的简化和MapReduce实现提供的服务质量在分布式计算社区上吸引了很多的热情.把MapReduce应用到多种科学应用的这么多 ...

  4. MapReduce 计算框架如何运作

    learn from 从0开始学大数据(极客时间) 1. MapReduce 作业启动和运行机制 作业涉及三类关键进程: 大数据应用进程 这类进程是启动 MapReduce 程序的主入口,主要是指定 ...

  5. Big Data(七)MapReduce计算框架(PPT截图)

    一.为什么叫MapReduce? Map是以一条记录为单位映射 Reduce是分组计算 转载于:https://www.cnblogs.com/littlepage/p/11156617.html

  6. 计算map代码_大数据系列之计算框架MapReduce

    CDA数据分析师 出品 1. MapReduce计算框架简介 Mapreduce 是hadoop项目中的分布式运算程序的编程框架,是用户开发"基于hadoop的数据分析应用"的核心 ...

  7. spark 算子例子_10年大数据架构师,用一文带你玩转Spark计算框架,你能读懂吗?...

    首先明确一点:学计算框架主要就是学2部分: 1.资源调度 2.任务调度 写一个spark程序包含加载配置文件,创建上下文,创建RDD , 调用RDD的算子,用户在算子中自定义的函数 map端:狭窄的理 ...

  8. mapreduce软件框架中作业与任务的含义

    MapReduce 综述(mapreduce软件框架中作业与任务的含义) MapReduce是一种计算模型,该模型可以将大型数据处理任务分解成很多单个的.可以在服务器集群中并行执行的任务,而这些任务的 ...

  9. MapReduce 分布式计算框架 简介 特点 工作流程

    MapReduce 计算框架 一种分布式计算框架,解决海量数据的计算问题 MapReduce将整个并行计算过程抽象到两个函数 Map(映射):对一些独立元素组成的列表的每一个元素进行指定的操作,可以高 ...

  10. BigData之Hadoop:Hadoop框架(分布式系统基础架构)的简介(两大核心【HDFS存储和MapReduce计算】)、深入理解、下载、案例应用之详细攻略

    BigData之Hadoop:Hadoop框架(分布式系统基础架构)的简介(两大核心[HDFS存储和MapReduce计算]).深入理解.下载.案例应用之详细攻略 目录 Hadoop的简介(分布式系统 ...

最新文章

  1. VadR发布WebVR分析工具,为开发者提供用户数据分析
  2. FCN训练自己的数据集及测试
  3. 2019.04.09 电商25 结算功能1
  4. 【CodeForces - 632B】Alice, Bob, Two Teams (预处理,思维,前缀和后缀和)
  5. 继续努力奋斗,生活会更美好
  6. python鸭制作类代码_Python动态语言与鸭子类型详解
  7. 中小企业信息管理 巧用E-Cell
  8. 【零基础学Java】—Java 日期时间(三十一)
  9. 微信团队分享:iOS版微信的高性能通用key-value组件技术实践
  10. AJAX Accordion:可折叠面板的集合
  11. 初步搭建RocketMQ环境
  12. HAWQ取代传统数仓实践(一)——为什么选择HAWQ
  13. DLNA和UPnP是什么关系?通俗解释
  14. win10计算机属性快捷键,win 10 电脑常用快捷键汇总
  15. 微软mysql sqlhelper_微软SqlHelper详细解读
  16. javaScript常用案例
  17. java算法编程题:计算球的体积
  18. BC3.1精简版win7/10下不兼容问题的解决
  19. 数据结构考试的一些选择题
  20. mpvue利用painter生成海报

热门文章

  1. Go语言:交换两个整型变量的值
  2. 图像处理_如何保存浮点型数值的图像? (C++ / OpenCV)
  3. KL距离-Kullback-Leibler Divergence
  4. 主干网络系列(4) -ResNeXt: 批量残差网络-作用于深度神经网络的残差聚集变换
  5. 稀疏矩阵与 spdiags函数图解
  6. tensorflow学习笔记(3)梯度下降法进行曲线拟合和线性回归
  7. 基于点云的视觉引导系统
  8. HDU4508 完全背包
  9. [转]十五天精通WCF——第七天 Close和Abort到底该怎么用才对得起观众
  10. 【SQL篇章--CREATE TABLE】