C语言版的磁盘文件分片归并排序函数

本文介绍了一种用于磁盘文件排序的老式C函数,适用于大文件的分片归并排序。通过实例演示了如何使用该函数,并提供了源代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        这是一个很老的的C函数,用来实现大的磁盘文件排序。在以前DOS操作系统下,对磁盘文件的排序一般有3种方法:1、将磁盘文件装入内存排序,将排序结果保存到新的文件,这适用于很小的(64K以内)、不需要经常索引的文件;2、对磁盘文件按关键字进行分块排序后,形成一个索引文件。块的大小一般为512K,常采用B+树或者B-数算法,这种方法适用于需要经常索引的磁盘文件,如DBF文件;3、把磁盘文件分片排序后,形成很多排序片文件,然后将这些排序片文件合并起来,输出为一个排序文件,这种方法适用于很大的、但又不需要经常索引的磁盘文件。

        可见,在DOS有限的内存条件下,磁盘文件分片归并排序是使用比较广泛的一种外存储器排序算法。现在计算机的物理内存一般足够大(最小的也有256MB吧),Windows的虚拟内存更是多达4个GB(对每一个应用程序而言),这对于很多磁盘文件的内存排序应该是足够了,况且现在的记录文件都放在各种数据库中,所以磁盘文件分片归并排序算法可能没有市场了(不过内存多路归并排序还是有市场的)。作为怀旧,把代码贴在这里,以免“失传”!


/* *************************************************************************
*  文  件  名 : MERGE.H                                                   *
*  编  制  人 : 湖北省公安县统计局  毛 泽 发                              *
*  日      期 : 1991.8                                                    *
*************************************************************************
*/

#define  S_IREAD         0x0100
#define  S_IWRITE        0x0080

#if  defined(__TINY__) || defined(__SMALL__) || defined(__MENIUM__)
#define  SSIZE     25600    /* 排序缓冲区字节 */
#define  NULL      0
#else
#define  SSIZE     65024    /* 排序缓冲区字节 */
#define  NULL      0L
#endif
#define  MAXMERGE  4        /* 排序合并每趟每次最大片 */
#define  MAXMEREC  (SSIZE / (MAXMERGE + 1)) /* 文件最大记录长 */

typedef 
int  cdecl mercmpf( const   void   * const   void   * );

/*  通用排序函数.
     参  数:排序文件名;原文件名;原文件头字节数;文件记录长;用户提供的比较函数.
     返回值:成功 > 0;内存不够.记录超长返回 0;文件操作出错 -1 
*/
int  fmerge( char   * foname,  char   * finame,  int  ftops,  int  lrd, mercmpf  * cmpf);

 


/* *************************************************************************
*  文  件  名 : MERGE.C                                                   *
*  编  制  人 : 湖北省公安县统计局  毛 泽 发                              *
*  日      期 : 1991.8                                                    *
*************************************************************************
*/

#include 
< io.h >
#include 
< string .h >
#include 
< fcntl.h >
#include 
< stdio.h >
#include 
< stdlib.h >
#include 
" merge.h "

static  mercmpf  * mercmp = NULL;    /*  比较函数  */

static   char   * merbuf  =  NULL;   /*  排序动态缓冲区  */
static   char   * filetop  =  NULL;  /*  原文件文件头存放动态缓冲区  */
static   int  filetopchs;        /*  原文件文件头长  */
static   int  merlrd;            /*  文件记录长  */

static   int  outfile( char   * fname, unsigned size,  int  flag);
static   int  formerge( char   * foname,  char   * finame,  char   * tmp, unsigned m);
static  domerge( char   * foname,  char   * tmp1,  char   * tmp2,  int  irun);
static   void  smerge( int   * md,  int  m,  char   * buf[],  int  outf,  char   * outbuf,  int  size);
static   int  dopass( char   * name1,  char   * name2,  int  irun);

/*  通用排序函数.
     参  数:排序文件名;原文件名;原文件头字节数;文件记录长;用户提供的比较函数.
     返回值:成功 > 0;内存不够.记录超长返回 0;文件操作出错 -1 
*/
int  fmerge( char   * foname,  char   * finame,  int  ftops,  int  lrd, mercmpf  * cmpf)
{
  
char  tmp1[ 68 ], tmp2[ 68 ];
  
int  irun;
  unsigned size;
  
if (lrd  >  MAXMEREC)  return   0 ;    /*  记录超长  */
  merlrd 
=  lrd;
  size 
=  (SSIZE  /  lrd)  *  lrd;     /*  排序缓冲区实际长  */
  
if ((merbuf  =  ( char   * )malloc(size))  ==  NULL)  return   0 /*  分配动态缓冲区  */
  
if (ftops  &&  (filetop  =  ( char   * )malloc(ftops))  ==  NULL)  return   0 ;
  filetopchs 
=  ftops;
  mercmp 
=  cmpf;
  strcpy(tmp1, 
" &&&1 " );    /*  临时文件名  */
  strcpy(tmp2, 
" &&&2 " );
  irun 
=  formerge(foname, finame, tmp1, size);  /*  分片排序  */
  
if (irun  >   1 )                                  /*  如果排序片大于 1  */
    irun 
=  domerge(foname, tmp1, tmp2, irun);   /*  合并排序片  */
  free(merbuf);
  
if (filetopchs) free(filetop);
  
return  irun;
}
/*  写一排序片文件  */
static   int  outfile( char   * fname, unsigned size,  int  flag)
{
  
int  h, c;
  
if ((h  =  open(fname, O_WRONLY  |  O_CREAT  |  O_TRUNC  |  O_BINARY, S_IWRITE))  ==   - 1 )
    
return   - 1 ;
  
if (flag  &&  filetopchs)  /*  如果是最终文件同时原文件有文件头  */
    write(h, filetop, filetopchs); 
/*  写入文件头内容  */
  c 
=  write(h, merbuf, size);       /*  写排序片到文件  */
  close(h);
  
return  c;
}
/*  分片排序  */
static   int  formerge( char   * foname,  char   * finame,  char   * tmp, unsigned m)
{
  unsigned irun, ret;
  
int  f, flag  =   0 ;
  
char  tmpname[ 68 ];
  
if ((f  =  open(finame, O_RDONLY  |  O_BINARY))  ==   - 1 return   - 1 ; /*  打开原文件  */
  
if (filetopchs)    /*  如有文件头,保存其内容到缓冲区  */
    read(f, filetop, filetopchs);
  irun 
=   0 ;
  
do {
    ret 
=  read(f, merbuf, m);   /*  读一排序片到排序缓冲区  */
    
if (ret  ==   0   ||  ret  ==   0xffff break /*  原文件结束或出错,退出  */
    qsort(merbuf, ret 
/  merlrd, merlrd, mercmp);  /*  排序  */
    
if (ret  ==  m  ||  irun  >   0 )    /*  如原文件长大于或等于一排序片长  */
      sprintf(tmpname, 
" %s.%03d " , tmp, irun);  /*  采用临时文件名  */
    
else {                       /*  否则,直接用排序文件名  */
      strcpy(tmpname, foname);
      flag 
=   1 ;                 /*  最终文件标记  */
    }
    ret 
=  outfile(tmpname, ret, flag);  /*  写排序片  */
    irun 
++ ;
  }
while (ret  ==  m);
  close(f);
  
if (ret  ==   0xffff return  ret;   /*  出错返回 -1  */
  
return  irun;                    /*  返回排序片数  */
}
/*  分配每一合并趟不同临时文件名;控制合并趟数  */
static  domerge( char   * foname,  char   * tmp1,  char   * tmp2,  int  irun)
{
  
char   * p;
  
while (irun  >   1 ){
    
if (irun  <=  MAXMERGE) strcpy(tmp2, foname);
    irun 
=  dopass(tmp1, tmp2, irun);
    p 
=  tmp1;
    tmp1 
=  tmp2;
    tmp2 
=  p;
  }
  
return  irun;
}
/*  执行合并趟,计算.分配每次合并所需文件数,缓冲区大小,控制每次合并的执行  */
static   int  dopass( char   * name1,  char   * name2,  int  irun)
{
  
int  fi, i, nrun, m, size;
  
char  oname[ 68 ], inname[ 68 ],  * p[MAXMERGE],  * q;
  
int  md[MAXMERGE], fo;
  size 
=  SSIZE  /  merlrd;   /*  合并缓冲区容纳记录数  */
  nrun 
=   0 ;
  
for (fi  =   0 ; fi  <  irun; fi  +=  MAXMERGE){
    m 
=  irun  -  fi;     /*  每次合并实际排序片数  */
    
if (m  >  MAXMERGE) m  =  MAXMERGE;
    
for (i  =   0 ; i  <  m; i  ++ ) p[i]  =  merbuf  +  (i  *  merlrd);  /*  分配读缓冲区  */
    
if (irun  <=  MAXMERGE) strcpy(oname, name2);  /*  最终合并形成排序文件  */
    
else  sprintf(oname,  " %s.%03d " , name2, nrun); /*  中间合并采用临时文件  */
    
if ((fo  =  open(oname, O_WRONLY  |  O_CREAT  |  O_TRUNC  |  O_BINARY, S_IWRITE))  ==   - 1 )
      
break ;   /*  打开写文件  */
    i 
=   0 ;
    
do /*  分别打开读文件  */
      sprintf(inname, 
" %s.%03d " , name1, fi  +  i);
      md[i] 
=  open(inname, O_RDONLY  |  O_BINARY);
    }
while (md[i  ++ !=   - 1   &&  i  <  m);
    
if (i  !=  m){
      close(fo);
      
for (fi  =   0 ; fi  <  i; fi  ++ ) close(md[fi]);
      
break ;
    }
    
if (irun  <=  MAXMERGE  &&  filetopchs)  /*  最终合并写文件头(如有)  */
      write(fo, filetop, filetopchs);
    q 
=  merbuf  +  (m  *  merlrd);         /*  分配写缓冲区  */
    smerge(md, m, p, fo, q, size 
-  m);  /*  合并  */
    
for (i  =   0 ; i  <  m; i  ++ ){   /*  删除各排序片文件  */
      close(md[i]);
      sprintf(inname, 
" %s.%03d " , name1, fi  +  i);
      unlink(inname);
    }
    close(fo);
    nrun 
++ ;
  }
  
if (nrun  !=  (irun  +  MAXMERGE  -   1 /  MAXMERGE)  return   - 1 ;
  
return  nrun;
}
/*  执行实际排序片合并  */
static   void  smerge( int   * md,  int  m,  char   * buf[],  int  outf,  char   * outbuf,  int  size)
{
  
int  i, j, n  =  merlrd, w  =  merlrd  *  size;
  
char   * =  buf[ 0 ],  * p,  * =  outbuf,  * end  =  q  +  w;
  
for (i  =   0 ; i  <  m; i  ++ )    /*  从各片文件中读第一条记录  */
    read(md[i], buf[i], n);
  
while ( 1 ){
    
if (n  ==  merlrd){         /*  如各片文件均有记录,各片记录反向插入排序  */
      
for (i  =   1 ; i  <  m; i  ++ ){
    
for (p  =  buf[i], j  =  i  -   1 ; j  >=   0   &&  mercmp(p, buf[j])  >   0 ; j  -- )
      buf[j 
+   1 =  buf[j];
    buf[j 
+   1 =  p;
      }
    }
    
else  m  -- ;   /*  一片文件内容结束  */
    
if ( ! m){      /*  如所有片文件结束,写缓冲区残余记录,退出  */
      
if (q  !=  outbuf) write(outf, outbuf, q  -  outbuf);
      
break ;
    }
    
if (q  ==  end){   /*  刷新一次写缓冲区到文件  */
      
if (write(outf, outbuf, end  -  outbuf)  !=  w)  break ;
      q 
=  outbuf;
    }
    i 
=  m  -   1 ;
    j 
=  (buf[i]  -  s)  /  merlrd;
    memmove(q, buf[i], merlrd); 
/*  将各片记录中值最小(大)者移入写缓冲区  */
    q 
+=  merlrd;
    n 
=  read(md[j], buf[i], merlrd);  /*  从该片中读下一记录,继续  */
  }
}

        可以看到,上面2个文件时间是1991年的,真是老古董了,如MERGE.H文件开头就没有什么诸如#ifndef        __MERGE_H......的代码,我记得那个时候好像没这个写法的。函数里面当初也作了很详细的注释,所以算法就不再讲了(要讲我还得先分析代码,早忘记了 ^_^ )。

        为了示范该函数的使用方法,我还是用BCB6写了一个简单的演示程序,如果你想试一下老古董,不妨也写一个?可以将MERGE.H文件中的排序缓冲区加大一些,可提高排序速度。

// ---------------------------------------------------------------------------
#include  < stdio.h >
#include 
< stdlib.h >
#include 
" merge.h "

#pragma  hdrstop

#define  TOPSTRING       "湖北省公安县统计局  毛 泽 发"
#define  TOP_SIZE        30
#define  RECORD_SIZE     53
#define  RECORD_COUNT    10000

// ---------------------------------------------------------------------------
/*
 为了方便观察,随机生成了一个RECORD_COUNT行的文本文件  */
void  MakeFile( char   * filename)
{
    
int  i, j;
    
long  v[ 4 ];
    FILE 
* f;
    f 
=  fopen(filename,  " w " );
    fprintf(f, 
" %s " , TOPSTRING);
    randomize();
    
for  (i  =   0 ; i  <  RECORD_COUNT; i  ++ )
    {
        
for  (j  =   0 ; j  <   4 ; j  ++ )
            v[j] 
=  random( 0x7fffffff );
        fprintf(f, 
" %12ld %12ld %12ld %12ld " , v[ 0 ], v[ 1 ], v[ 2 ], v[ 3 ]);
    }
    fclose(f);
}


int  cdecl CompRecord( const   void   * ra,  const   void   * rb)
{
    
int  a[ 4 ], b[ 4 ];
    
int  i, n;
    sscanf((
char * )ra,  " %ld%ld%ld%ld " & a[ 0 ],  & a[ 1 ],  & a[ 2 ],  & a[ 3 ]);
    sscanf((
char * )rb,  " %ld%ld%ld%ld " & b[ 0 ],  & b[ 1 ],  & b[ 2 ],  & b[ 3 ]);
    
for  (n  =   0 , i  =   0 ; i  <   4   &&  n  ==   0 ; i  ++ )
        n 
=  a[i]  -  b[i];
    
return  n;
}

#pragma  argsused
int  main( int  argc,  char *  argv[])
{
    printf(
" 正在随机制造一个文本文件d:/test.txt... " );
    MakeFile(
" d:/test.txt " );
    printf(
" 正在进行磁盘文件排序,排序文件d:/sort.text... " );
    fmerge(
" d:/sort.txt " " d:/test.txt " , TOP_SIZE, RECORD_SIZE, CompRecord);
    printf(
" 磁盘文件排序完毕! " );
    system(
" pause " );
    
return   0 ;
}
// ---------------------------------------------------------------------------

 

       如有错误,或者你有什么好的建议请来信:maozefa@hotmail.com

        发现代码贴上去总是走样,文件路径‘//’也成了‘/’,‘/n’也没了,MakeFile的2句写记录语句应该分别是,不然,测试会出问题:

fprintf(f, "%s/n", TOPSTRING);

fprintf(f, "%12ld %12ld %12ld %12ld/n", v[0], v[1], v[2], v[3]);

 

以下是将提供的内容转换为Markdown格式的文件: ```markdown # Hadoop-MapReduce 文档 ## 1. MapReduce 设计思想 ### 分而治之 - **对付大数据并行处理**:将大的数据切分成多个小数据,交给更多节点参与运算。 - 注意:不可拆分的计算任务或相互间有依赖关系的数据无法进行并行计算。 ### 抽象模型 - Input:读取数据。 - Split:对数据进行粗粒度切分。 - Map:对数据进行细粒度切分。 - Shuffle:洗牌,将各个 `MapTask` 结果合并输出到 `Reduce`。 - Reduce:对 `Shuffle` 进行汇总并输出到指定存储。 - Output:如 HDFS、Hive、Spark、Flume 等。 ### 统一架构 - 提供统一的计算框架,隐藏大多数系统层面处理细节,减轻程序员开发负担。 ### 特征 - **离线框架**:适合PB级别海量数据的离线处理。 - **不擅长实时计算**:不适合毫秒或秒级返回结果。 - **不擅长流式计算**:输入数据是动态的,而 MapReduce 输入数据集是静态的。 - **不擅长 DAG(有向图)计算**:多应用程序存在依赖关系时,性能低下。 ### 计算向数据靠拢 - 在数据节点上进行工作。 ### 顺序处理数据 - 规避随机访问数据,提升性能。 ### 失效被认为是常态 - 使用大量低端服务器,节点失效频繁。设计良好的并行计算系统应具备健壮性和容错性。 --- ## 2. 常用排序算法 ### 分类 #### 不值钱 - 学过计算机的基本都会的算法。 - 包括:冒泡排序、选择排序、插入排序。 #### 进阶型 - 更高效的算法。 - 包括:希尔排序(高级插入)、堆排序(高级选择)。 #### 常用型 - 实际应用广泛的算法。 - 包括:快速排序、归并排序。 #### 偏方型 - 在特定场景下有奇效。 - 包括:计数排序、桶排序、基数排序。 ### 快速排序 - **从冒泡排序演变而来**,实际上是递归分治法。 - **实现方式**:Hoare法(左右指针法)、前后指针法、挖坑法。 #### 左右指针法(Hoare法) - 第一个元素为 `Key`,`Begin` 和 `End` 分别指向第一个和最后一个元素。 - 操作直至 `Begin >= End`,交换 `Key` 和 `End` 的值,重复操作左右两边。 #### 挖坑法 - 挑选基准元素,所有小于基准值的元素置于左侧,大于的置于右侧。 - 示例:`arr = [5, 2, 4, 6, 1, 7, 8, 3]`,逐步调整,最终基准位于正确位置,再递归处理两侧子序列。 #### 前后指针法 - 初始设置 `Cur` 和 `Prev` 标志指针。 - `Cur` 前进,遇到小于基准值时交换 `Prev` 和 `Cur` 的值,保证 `Cur` 与 `Prev` 间元素均大于基准值。 #### 优化选 Key - 最佳情况:每次选取中间值。 - 引入“三数取中”,取首中尾三个元素的中间值作为基准,解决有序数组排序效率低下的问题。 ### 归并排序 - **基于归并操作**的有效排序算法。 - **基本思想**:将原序列不断拆分至单个元素,再按插入方式归并。 - 时间复杂度始终为 `O(n log n)`,但需要额外内存空间。 --- ## 3. MapReduce 计算流程 ### 计算1T数据中每个单词出现次数 -> wordcount #### 原始数据File - 数据被切分成块存放在 HDFS 上,每块 128M。 #### 数据块Block - 数据存储单元,同一文件中块大小相同。 - 可能块数量与集群计算能力不匹配,需动态调整参与计算的节点数量。 #### 切片Split - 控制参与计算的节点数目,切片大小为块的整数倍(2 或 1/2)。 - 默认情况下,切片大小等于块大小(默认 128M),一个切片对应一个 `MapTask`。 #### MapTask - 默认从所属切片读取数据,每次读取一行到内存。 - 计算每个单词出现次数,产生 `(Map<String, Integer>)` 临时数据,存放在内存中。 - 为了避免 `OOM` 和低效率,数据会周期性写入硬盘。 #### 环形数据缓冲区 - 循环利用内存区域,减少数据溢写时 `Map` 的停止时间。 - 每个 `Map` 单独占用一块内存区域,默认大小为 100M。 - 当缓冲区达到 80% 开始溢写,留出 20% 空间,确保效率不减缓。 #### 分区 Partation - 根据 `Key` 计算对应的 `Reduce`。 - 分区数量与 `Reduce` 数量相等,默认分区算法为哈希取余。 #### 排序 Sort - 对溢写数据进行排序(`QuickSort`),按 `Partation` 和 `Key` 排序,确保相同分区和 `Key` 在一起。 #### 溢写 Spill - 将内存数据写入硬盘,避免 `OOM` 问题。 - 每次产生一个 80M 文件,数据较多时可能多次溢写。 #### 合并 Merge - 将溢写产生的多个小文件合并成一个大文件,便于后续拉取数据。 - 合并过程中仍进行排序(归并排序),生成有序大文件。 #### 组合器 Combiner - 减少 `Map` 和 `Reduce` 间的数据传输。 - 自定义 `combiner` 函数,类似 `reduce` 函数,确保局部汇总结果不影响最终结果。 #### 拉取 Fetch - 将 `Map` 的临时结果拉取到 `Reduce` 节点。 - 确保相同 `Key` 拉取到同一个 `Reduce` 节点。 #### 归并 Reduce - 读取文件数据到内存,将相同 `Key` 全部读取并得出最终结果。 #### 写出 Output - 每个 `Reduce` 将最终结果存放到 HDFS 上。 --- ## 4. Hadoop-YARN 架构 ### 基本概念 - **Yarn**:另一种资源协调者,用于统一管理资源。 - **ResourceManager**:资源协调框架的管理者,分为主节点和备用节点。 - **NodeManager**:资源协调框架的执行者,每个 `DataNode` 上默认有一个 `NodeManager`。 - **ApplicationMaster**:负责调度被分配的资源 `Container`,任务完成后通知 `ResourceManager` 销毁资源。 - **Task**:开始按照 `MR` 流程执行业务。 ### 工作流程 - 根据 `mapreduce.framework.name` 变量配置选择运行时框架。 - `Client` 发起提交作业申请,`ResouceManager` 返回 `JobID` 并保存数据资源。 - `Client` 计算分片并将资源拷贝到 HDFS,最后提交 `Job` 给 `ResouceManager`。 - `ApplicationManager` 接收提交的 `Job` 并交由 `ResourceScheduler` 处理。 - `ApplicationMaster` 注册并与 `ResourceManager` 交互,申请资源并调度任务。 --- ## 5. Hadoop-YARN 环境搭建 ### 目标环境 - 基于 HA 环境搭建。 ### 修改配置文件 - 修改 `hadoop-env.sh`、`mapred-site.xml` 和 `yarn-site.xml` 文件。 - 添加必要的环境变量和配置项。 ### 拷贝至其他节点 - 将配置好的 YARN 拷贝至其他节点。 ### 启动 - 启动 ZooKeeper、HDFS 和 YARN。 - 启动 JobHistory。 ### 关闭 - 关闭 Hadoop 和 JobHistory,再关闭 ZooKeeper。 --- ## 6. MapReduce 案例 - WordCount ### Java代码实现 - 主要涉及 `WordCountJob` 类、`WordCountMapper` 类和 `WordCountReducer` 类。 - 设置 `Map` 输出的 `Key` 和 `Value` 类型,配置 `Map` 和 `Reduce` 的处理类。 ### 提交方式 - Linux端:`hadoop jar wordcount.jar com.yjxxt.mapred.wordcount.WordCountJob` ### YARN常用命令 - 查看节点:`yarn node-list-all` - 查看所有 Application:`yarn application-list` - 杀死 Application:`yarn application-kill <application_id>` - 查看 Application 日志:`yarn logs -applicationId <application_id>` --- ## 7. MapReduce 案例 - 充值记录 ### Mock数据 - 自动生成一万条充值记录,模拟用户行为。 - 按照性别分类统计男女性用户的充值总额。 --- ## 8. MapReduce 案例 - 天气信息 ### 需求 - 每个地区的每日最高温及最低温。 - 每月温度最高的三天。 --- ## 9. MapReduce 案例 - 好友推荐 ### 需求 - 根据互为好友的关系,进行好友推荐。 --- ## 10. MapReduce 压缩 ### 概述 - 压缩技术能减少存储读写字节数,提高网络带宽和磁盘空间效率。 - 压缩在大数据环境中尤为重要,特别是在 I/O 密集型作业中。 ### 压缩实践 - 支持的压缩格式及其特点见表格。 - 压缩应用场景的选择依据。 --- ## 11. MapReduce 源码分析 ### Split - 创建切片文件,设置切片数量。 ### MapTask - 初始化 `MapTask`,读取输入并执行 `Mapper` 方法。 ### KvBuffer - 初始化环形缓冲区,设置溢写阈值。 ### Spill - 将缓冲区数据溢写到磁盘。 ### Merge - 合并溢写文件,减少磁盘 I/O 次数。 ### ReduceTask - 获取 `Key` 和 `Value` 的迭代器,执行 `Reducer` 方法。 --- ## 12. MapReduce 优化 ### 概述 - 明确 Hadoop 的优势和适用场景,了解 MapReduce 执行流程。 ### 小文件优化 - 使用 `CombineFileInputFormat` 读取数据时合并小文件。 ### 数据倾斜 - 解决方法包括自定义分区、增加 Reduce 的资源或调整 Reduce 数量。 ### 推测执行 - 开启推测执行,空间换时间,提高作业性能。 ### MapReduce 执行流程优化 - **Map** - **临时文件**:合理设置文件副本数量。 - **分片**:调整分片大小以动态设置 Map 数量。 - **资源**:根据业务需求调整 Map 的资源。 - **环形缓冲区 & 溢写**:调整缓冲区大小和溢写百分比。 - **合并**:增加合并因子,减少合并次数。 - **输出**:使用组合器和压缩减少数据传输。 - **Reduce** - **资源**:合理设置 Reduce 数量和资源。 - **拉取**:调整拉取并行度和超时时间。 - **缓冲区 & 溢写**:基于 JVM Heap Size 设置缓冲区大小。 - **合并**:增加合并因子,减少磁盘操作。 - **读缓存**:启用读缓存以减少磁盘 I/O。 --- ``` 此 Markdown 文件包含了原文档的主要内容,并遵循 Markdown 语法进行了适当的格式化,使其更易于阅读和理解。希望这对您有所帮助!如果您有任何进一步的需求,请告知我。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值