HBase与MapReduce整合:TableMapper与TableReducer部分源码分析

2023-11-07

目录

关于TableMapper和TableReducer

TableMapReduceUtil

initTableMapperJob

initTableReducerJob

TableInputFormat

TableRecordReader

TableOutputFormat


关于TableMapper和TableReducer

在自定义TableMapper时需要指定两个泛型,即K2和V2的数据类型。K1默认为ImmutableBytesWritable即行键(从hbase中读取到是字节数组),V2默认为Result类型,也就是说一行可能会Get到多个列,这和Hbase的按列存储的存储方式相同,通过Mapper获取到表的数据可以看成在hbase shell中scan得到的结果是类似的,可以说普通的Mapper会对每个kv对调用一次map()函数,而TableMapper是对每列调用一次map()函数(k为行键,v为单元格)

public abstract class TableMapper<KEYOUT, VALUEOUT>
extends Mapper<ImmutableBytesWritable, Result, KEYOUT, VALUEOUT>

而自定义TableReducer时需要指定三个泛型,分别为K2,V2和K3的类型。V3默认是org.apache.hadoop.hbase.client.Mutation类型,也就是具体的Put或Delete实例。在reduce()方法中需要写出K3,V3,此时K3的具体内容并不重要,可以通过下面的源码发现后续并没有对K3进行操作。因为Put或Delete实例当中已经包含了本来应该是K3的行键,而TableReducer中使用的Context是org.apache.hadoop.mapreduce.TaskInputOutputContext,该类中只有传入两个参数的write(),作者估计是懒得写一个特殊的Context而直接使用了通用的TaskInputOutputContext,所以write()方法中的第一个参数没有什么意义

public abstract class TableReducer<KEYIN, VALUEIN, KEYOUT>
extends Reducer<KEYIN, VALUEIN, KEYOUT, Mutation> {
}

TableMapReduceUtil

可以通过TableMapReduceUtil类来创建Mapper和Reducer的任务

initTableMapperJob

在上篇中进行hbase中表复制

//参数分别为:表名,扫面器,Mapper类,K2类型,V2类型,任务Job
TableMapReduceUtil.initTableMapperJob(oldTableName, scan, MyMapper.class, Text.class,Text.class,job);

一共6个参数,而其实上底层会自动增加一些参数进行调整,底层方法为

public static void initTableMapperJob(String table, Scan scan,
      Class<? extends TableMapper> mapper,
      Class<?> outputKeyClass,
      Class<?> outputValueClass, Job job,
      boolean addDependencyJars, boolean initCredentials,
      Class<? extends InputFormat> inputFormatClass)
  throws IOException

参数分析

  • table:表名,用户传入
  • scan:扫描器,用户传入
  • mapper:Mapper类,用户传入
  • outputKeyClass:Mapper输出Key的类型,用户传入
  • outputValueClass:Mapper输出Value的类型,用户传入
  • job:可能仅读取了hdfs有关配置文件的任务,需要确保加载了hbase有关配置参数,用户传入
  • addDependencyJars:是否需要加载hbase有关jar包,默认为true
  • initCredentials:是否需要为作业初始化与hbase之间的连接验证,默认为true
  • inputFormatClass:输入格式,默认为TableInputForamt
    //设置输入格式,inputFormatClass为TableInputFormat
    job.setInputFormatClass(inputFormatClass);
    //设置K2,V2数据类型,若为空则会在以后setOutputKey/ValueClass中设置
    if (outputValueClass != null) job.setMapOutputValueClass(outputValueClass);
    if (outputKeyClass != null) job.setMapOutputKeyClass(outputKeyClass);
    //设置Mapper类,mapper为MyMapper.class
    job.setMapperClass(mapper);
    //若V2为Put类,设置Combiner类为PutCombiner.class
    if (Put.class.equals(outputValueClass)) {
      job.setCombinerClass(PutCombiner.class);
    }
    Configuration conf = job.getConfiguration();
    //将原来的conf对象与通过HBaseConfiguration创建的conf进行融合,这一步是为了确保读取到了hbase-site.xml中的属性
    HBaseConfiguration.merge(conf, HBaseConfiguration.create(conf));
    //设置要读取的表,可以理解为输入路径
    conf.set(TableInputFormat.INPUT_TABLE, table);
    //设置TableInputFormat的扫描器,因为实际上是TableRecordReader在进行读
    conf.set(TableInputFormat.SCAN, convertScanToString(scan));
    //加载序列化有关类
    conf.setStrings("io.serializations", conf.get("io.serializations"),
        MutationSerialization.class.getName(), ResultSerialization.class.getName(),
        KeyValueSerialization.class.getName());
    if (addDependencyJars) {
      //在classpath下加载jar包,如hbase-common-1.3.1.jar、hbase-client-1.3.1.jar等等
      //以及其他jar包
      addDependencyJars(job);
    }
    if (initCredentials) {
      //初始化job与hbase的连接验证
      initCredentials(job);
    }

在addDependencyJars中不光加载了conf中的jar包,还有以下jar包

  public static void addDependencyJars(Job job) throws IOException {
    addHBaseDependencyJars(job.getConfiguration());
    try {
      addDependencyJarsForClasses(job.getConfiguration(),
          job.getMapOutputKeyClass(),
          job.getMapOutputValueClass(),
          job.getInputFormatClass(),
          //!默认为LongWritable
          job.getOutputKeyClass(),
          //默认为Text
          job.getOutputValueClass(),
          job.getOutputFormatClass(),
          job.getPartitionerClass(),
          job.getCombinerClass());
    } catch (ClassNotFoundException e) {
      throw new IOException(e);
    }
  }

所以与其他输入格式相同,真正从客户端读数据的部分是在阅读器TableRecordReader实现的,initTableMapperJob仅仅是为TableInputFormat指定一些描述性参数以供TableRecordReader使用

TableInputFormat

TableInputFormat继承于TableInputFormatBase

TableInputFormatBase中的属性

  private Scan scan = null;
  private Admin admin;
  private Table table;
  //分区器
  private RegionLocator regionLocator;
  //阅读器实例
  private TableRecordReader tableRecordReader = null;
  private Connection connection;

InputFormat无非有两个功能:创建阅读器TableRecordReader和进行分片、如何分片暂不关心

在初始化中创建阅读器

  @Override
  public RecordReader<ImmutableBytesWritable, Result> createRecordReader(
      InputSplit split, TaskAttemptContext context)
  throws IOException {

    TableSplit tSplit = (TableSplit) split;
    final TableRecordReader trr =
        this.tableRecordReader != null ? this.tableRecordReader : new TableRecordReader();
    //从用户传入的扫描器中获取属性构造内部扫描器
    Scan sc = new Scan(this.scan);
    sc.setStartRow(tSplit.getStartRow());
    sc.setStopRow(tSplit.getEndRow());
    //将扫描器传给阅读器TableRecordReader
    trr.setScan(sc);
    //将表传给阅读器TableRecordReader
    trr.setTable(getTable());
    //这个阅读器其实上全是调用TableRecordReader上的方法实现阅读
    return new RecordReader<ImmutableBytesWritable, Result>() {
      @Override
      public void close() throws IOException {
        trr.close();
        closeTable();
      }
      @Override
      public ImmutableBytesWritable getCurrentKey() throws IOException, InterruptedException {
        return trr.getCurrentKey();
      }
      @Override
      public Result getCurrentValue() throws IOException, InterruptedException {
        return trr.getCurrentValue();
      }
      @Override
      public float getProgress() throws IOException, InterruptedException {
        return trr.getProgress();
      }
      @Override
      public void initialize(InputSplit inputsplit, TaskAttemptContext context) throws IOException,
          InterruptedException {
        trr.initialize(inputsplit, context);
      }
      @Override
      public boolean nextKeyValue() throws IOException, InterruptedException {
        return trr.nextKeyValue();
      }
    };
  }

所以具体的实现还是由TableRecordReader来完成的

TableRecordReader

TableRecordReader内部实际上创建了阅读器的具体实现类TableRecordReaderImpl对象

我们需要关注的是initialize()与nextKeyValue()方法

initialize():

  public void initialize(InputSplit inputsplit,
      TaskAttemptContext context) throws IOException,
      InterruptedException {
    if (context != null) {
      this.context = context;
      //计数器有关
      getCounter = retrieveGetCounterWithStringsParams(context);
    }
    //生成一个内部的扫描器
    restart(scan.getStartRow());
  }

实际上读数据时在 restart()中实现的,得到了ResultScanner实例

  public void restart(byte[] firstRow) throws IOException {
	//对表的扫描实际上是在内部的currentScan实现的,将TableInputFormat传入的扫描器相关属性获取给currentScan
	//同时可以从可生存的异常中重新创建扫描器
    currentScan = new Scan(scan);
    currentScan.setStartRow(firstRow);
    currentScan.setScanMetricsEnabled(true);
    if (this.scanner != null) {
      this.scanner.close();
    }
    //在这里读取到了表数据,返回ResultScanner类型
    this.scanner = this.htable.getScanner(currentScan);
    if (logScannerActivity) {
      rowcount = 0;
    }
  }

nextKeyValue():

  public boolean nextKeyValue() throws IOException, InterruptedException {
	//构造K1,V1
    if (key == null) key = new ImmutableBytesWritable();
    if (value == null) value = new Result();
    try {
      try {
    	//遍历ResultScanner  
        value = this.scanner.next();
        //读取到了一个单元格作为V1
        if (value != null && value.isStale()) numStale++;
        
      } catch (IOException e) {
        if (e instanceof DoNotRetryIOException) {
          throw e;
        }
        //遇到IOExceptions时尝试重新重建扫描器,即调用restart()。若调用失败,异常再次抛出
        if (lastSuccessfulRow == null) {
          //即没有成功读取的行,重建扫描器,从头开始
          restart(scan.getStartRow());
        } else {
          //在成功读取到行的基础上重建扫描器	
          restart(lastSuccessfulRow);
          scanner.next();    
        }
        //若此时扫描正常了,该干啥干啥,这里没有使用递归,所以扫描器最多只能出错一次
        value = scanner.next();
        if (value != null && value.isStale()) numStale++;
        numRestarts++;
      }
      if (value != null && value.size() > 0) {
        key.set(value.getRow());
        lastSuccessfulRow = key.get();
        return true;
      }

      updateCounters();
      return false;
    } catch (IOException ioe) {
      //扫描器第二次出错时,没救了,直接抛出
      throw ioe;
    }
  }

 

initTableReducerJob

在上篇中进行hbase中表复制

//参数分别为:表名(String),Reducer类,任务Job
TableMapReduceUtil.initTableReducerJob("wordcount_copy", MyReducer.class, job);

同样底层添加了一些参数

  public static void initTableReducerJob(
    String table,
    Class<? extends TableReducer> reducer, 
    Job job,
    Class partitioner, 
    String quorumAddress, 
    String serverClass,
    String serverImpl, 
    boolean addDependencyJars) throws IOException

与initTableMapperJob比较类似,不过多了一些与集群地址,服务器端地址有关的参数,毕竟要写到hbase上

有了阅读有关TableMapper的经验后,接下来TableReducer端的阅读轻松了不少

    Configuration conf = job.getConfiguration();
    HBaseConfiguration.merge(conf, HBaseConfiguration.create(conf));
    job.setOutputFormatClass(TableOutputFormat.class);
    if (reducer != null) job.setReducerClass(reducer);
    conf.set(TableOutputFormat.OUTPUT_TABLE, table);
    conf.setStrings("io.serializations", conf.get("io.serializations"),
        MutationSerialization.class.getName(), ResultSerialization.class.getName());
    // 设置zk集群地址
    if (quorumAddress != null) {
      ZKConfig.validateClusterKey(quorumAddress);
      conf.set(TableOutputFormat.QUORUM_ADDRESS,quorumAddress);
    }
    //提供serverClass、serverImp以供对hbase服务器交互
    if (serverClass != null && serverImpl != null) {
      conf.set(TableOutputFormat.REGION_SERVER_CLASS, serverClass);
      conf.set(TableOutputFormat.REGION_SERVER_IMPL, serverImpl);
    }
    //K3类型为ImmutableBytesWritable,虽然K3没啥用
    job.setOutputKeyClass(ImmutableBytesWritable.class);
    //V3类型为父类Writable,可在Driver类中设置覆盖
    job.setOutputValueClass(Writable.class);
    if (partitioner == HRegionPartitioner.class) {
      job.setPartitionerClass(HRegionPartitioner.class);
      //Reducer个数为region数
      int regions = MetaTableAccessor.getRegionCount(conf, TableName.valueOf(table));
      if (job.getNumReduceTasks() > regions) {
        job.setNumReduceTasks(regions);
      }
    } else if (partitioner != null) {
      job.setPartitionerClass(partitioner);
    }

    if (addDependencyJars) {
      //若在Mapper之后改变了配置属性,重新加载一遍jar包
      addDependencyJars(job);
    }

    initCredentials(job);

TableOutputFormat

再此创建了RecordWriter实现写到hbase,与TableInputFormat不同的是,RecordWriter是TableOutputFormat的内部类

重点关心以下TableRecordWriter下的write()方法

    public void write(KEY key, Mutation value)
    throws IOException {
      //K3只能是Put或Delete实例
      if (!(value instanceof Put) && !(value instanceof Delete)) {
        throw new IOException("Pass a Delete or a Put");
      }
      mutator.mutate(value);
    }

具体的写操作是通过BufferedMutator实例的mutate()方法写出去的

public void mutate(List<? extends Mutation> ms){
//...
    for (Mutation m : ms) {
      if (m instanceof Put) {
        validatePut((Put) m);
      }
      toAddSize += m.heapSize();
    }
//...
}
  public void validatePut(final Put put) throws IllegalArgumentException {
    HTable.validatePut(put, maxKeyValueSize);
  }

可见最终由HTable实例写进去的,maxKeyValueSize为10485760即10M,这个方法同put()相比不过是对行数据大小进行了限制,即一行不能超过10M

  public static void validatePut(Put put, int maxKeyValueSize) throws IllegalArgumentException {
    if (put.isEmpty()) {
      throw new IllegalArgumentException("No columns to insert");
    }
    if (maxKeyValueSize > 0) {
      for (List<Cell> list : put.getFamilyCellMap().values()) {
        for (Cell cell : list) {
          if (KeyValueUtil.length(cell) > maxKeyValueSize) {
            throw new IllegalArgumentException("KeyValue size too large");
          }
        }
      }
    }
  }

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

HBase与MapReduce整合:TableMapper与TableReducer部分源码分析 的相关文章

  • Apache Phoenix - 如何在 Kerberos 集群上启动查询服务器和瘦客户端

    我最近花了几天时间尝试通过zookeeper运行phoenix Thin queryserver py和sqlline thin py 和thick以保护集群 但是 我无法在安全集群上启动或连接phoenix服务 在phoenix瘦客户端和
  • 将数据从一个 hbase 表复制到另一个 hbase 表

    我创建了一个表 hivetest 它还在 hbase 中创建了名为 hbasetest 的表 现在我想将 hbasetest 数据复制到具有相同架构的另一个 hbase 表 例如 logdata 中 那么 任何人都可以帮助我如何在不使用配置
  • 运输例外

    我正在尝试导入 happybase 但在连接时收到以下错误消息 我已经运行了 Hadoop 伪节点集群和 Hbase 安装的组件版本如下 Hadoop 版本 1 0 4 Hbase 版本 0 94 4 快乐基地 0 4 有人可以查看下面的例
  • Java中通过忽略开始行和结束行的一部分来扫描HBase行

    我的 HBase 行如下 ABC A1 20160101 ABC A2 20160102 ABC A3 20160103 XYZ A9 20160201 从我的Java代码中我知道第一部分ABC和最后一部分20160101 我没办法得到中间
  • 设置HBase、hadoop、hive通过hive访问Hbase的正确方法是什么?

    我在配置和安装 hbase hadoop hive 时遇到问题 到目前为止我在 ubuntu 14 04 3 LTS 的虚拟机上做了什么 像这样安装了jdk和版本jdk1 8 0 60 https askubuntu com questio
  • HBASE SPARK 带过滤器的查询,无需加载所有 hbase

    我必须查询 HBASE 然后使用 Spark 和 scala 处理数据 我的问题是 通过我的解决方案 我获取 HBASE 表的所有数据 然后进行过滤 这不是一种有效的方法 因为它占用了太多内存 所以我想直接做过滤器 我该怎么做 def Hb
  • HBase:复制是如何工作的?

    我目前正在将 HBase 作为数据存储进行评估 但有一个问题没有得到解答 HBase 在许多节点上存储同一对象的许多副本 也称为复制 由于HBase具有所谓的强一致性 相比之下最终一致 它保证每个副本在读取时返回相同的值 据我了解 HBas
  • 在 Java 中连接来自 HBase 的两个结果集?

    是否可以连接从 java 中的 hbase 检索的两个或多个结果集 不 不可能加入 JDBC 结果集 但是 您可以获取它们的结果并手动组合它们 如果它们兼容 如果它们属于同一实体 EDIT 如果您只需要组合两个相同类型的列表 您可以这样做
  • 将 Spark 数据帧插入 hbase

    我有一个数据框 我想将其插入到 hbase 中 我遵循这个文档 https hbase apache org book html sparksql dataframes 这就是我的数据框的样子 id name address 23 marr
  • Spark 2 的 hbase-spark

    我想要进行全面扫描hbase from Spark 2 using Scala 我没有固定的目录定义 因此库为SHC https github com hortonworks spark shc不是一个选择 我的逻辑选择是使用 hbase
  • 使用 Spark 和 Phoenix 将 CSV 文件保存到 hbase 表

    有人可以向我指出使用 Spark 将 csv 文件保存到 Hbase 表的工作示例吗2 2我尝试过但失败的选项 注意 它们都适用于我的 Spark 1 6 凤凰火花 hbase spark it nerdammer bigdata spar
  • 我的 cdh5.2 集群在运行 hbase MR 作业时出现 FileNotFoundException

    我的 cdh5 2 集群运行 hbase MR 作业时出现问题 例如 我将 hbase 类路径添加到 hadoop 类路径中 vi etc hadoop conf hadoop env sh 添加行 export HADOOP CLASSP
  • Spark Streaming数据放入HBase的问题

    我是这个领域的初学者 所以我无法理解它 HBase 版本 0 98 24 hadoop2 火花版本 2 1 0 以下代码尝试将从 Spark Streming Kafka 生产者接收的数据放入 HBase 中 Kafka输入数据格式是这样的
  • security.UserGroupInformation:MR 的 PrivilegedgedActionException 错误

    每当我尝试执行映射缩减作业以写入 Hbase 表时 我都会在控制台中收到以下错误 我正在从用户帐户运行 MR 作业 错误 security UserGroupInformation PriviledgedActionException 为
  • Titan-1.0.0+Hbase-0.98.20使用java远程模式连接错误

    我正在学习Titan数据库 我已经在本地模式下成功运行了它 现在 我尝试在 Titan 文档中介绍的 远程服务器模式 下使用 Titan 数据库 我的 Titan 版本是 Titan 1 0 0 hadoop1 我的 LAN 中有集群 包括
  • 错误:org.apache.hadoop.hbase.MasterNotRunningException:null+hbase+hadoop

    我最近用两台机器 在ubuntu上 配置了hadoop集群 到目前为止效果很好 但是当我尝试在上面的 hadoop 集群上配置 hbase 时 它 显示错误 这就是我所做的 我有两台机器 192 168 1 110 Hadoop主站 192
  • 在hbase中创建表

    我是 hbase 和 hadoop 的新手 无论如何 我已经成功建立了一个由3台机器组成的hadoop集群 现在我需要一些帮助来建立数据库 我有一个表 评论 包含字段 user id comments 对评论的评论 可以多个 和状态字段相同
  • 将多个前缀行过滤器设置为扫描仪 hbase java

    我想创建一台扫描仪 它可以为我提供带有 2 个前缀过滤器的结果例如 我想要其键以字符串 x 开头或以字符串 y 开头的所有行 目前我知道只能使用一个前缀 方法如下 scan setRowPrefixFilter prefixFiltet 在
  • 无法从 HBase 导出表

    我无法将表从 HBase 导出到 HDFS 下面是错误跟踪 它的尺寸相当大 还有其他方法可以导出吗 我使用下面的命令来导出 我增加了 rpc 超时但作业仍然失败 sudo u hdfs hbase Dhbase rpc timeout 10
  • Janusgraph 0.3.2 + HBase 1.4.9 - 无法设置 graph.timestamps

    我在 Docker 容器中运行 Janusgraph 0 3 2 并尝试使用运行 HBase 1 4 9 的 AWS EMR 集群作为存储后端 我可以运行 gremlin server sh 但如果我尝试保存某些内容 我会得到粘贴在下面的堆

随机推荐

  • TypeScript中的keyof、typeof、索引访问类型、条件类型

    一 keyof类型操作符 TypeScript中的keyof类型操作符可以获取某个类型的所有属性名组成的联合类型 这个操作符的作用是帮助开发者在静态类型检查中更准确地操作属性名 举例来说 如果我们有如下一个接口 interface Pers
  • Xcode多视图应用Tab Bar Controller、Table View Controller2021-04-10

    1 视图控制器 首先应该理解Xcode里的视图控制器一般以controller结尾 在storyboard中添加的每一个视图控制器都有一个默认的名字如View Controller 标识符 可以修改视图控制器的title属性 改它的名字 点
  • 编译执行与解释执行的区别

    今天在看到一篇关于分层编译优化的文章时 看到了解释执行与编译执行两个专业词汇 看着熟悉 但不甚理解 然后在网上搜索了一下 说一下自己的理解 对于我们平时写的代码 一般计算机是没办法直接识别的 需要相应的编译器将其编译层机器代码 一些计算机可
  • AI绘画关键词网站推荐 :轻松获取百万个提示词!完全免费

    一 lexica art 该网站拥有数百万Stable Diffusion案例的文字描述和图片 可以为大家提供足够的创作灵感 使用上也很简单 只要在搜索框输入简单的关键词或上传图片 就能为你提供大量风格不同的照片 点击照片就能看到完整的AI
  • uniapp调用地图,进行位置查询,标记定位

    这周开会又新增一个小功能 就是需要通过身份证号 手机号在地图查询 后台返回经纬度 标记位置 想着挺麻烦 做的时候发现没啥技术 分享给大家
  • JDK,JRE和JVM三者间关系

    JDK是什么 JDK Java Development Kit Java开发工具包 是针对Java开发程序员的产品 是整个Java的核心 包含Java运行环境JRE Java工具和Java基础类库 具有3个主要组成部分 1 Java 编程语
  • java重试工具库: 实现业务逻辑与重试逻辑的解耦

    对于开发过网络应用程序的程序员来说 重试并不陌生 由于网络的拥堵和波动 此刻不能访问服务的请求 也许过一小段时间就可以正常访问了 比如下面这段给某个手机号发SMS的伪代码 发送SMS public boolean sendSMS Strin
  • chrome打开开发者工具(F12)之后看不到请求头信息

    开发者工具的network窗口能够查看浏览器的请求头以及响应头信息 但是有时打开开发者工具会遇到像下图这种情况 找不到请求信息 无法查看请求头 或响应头 解决方法 点击 Filter 按钮 也就是图中的漏斗形状的按钮 下面会多出一系列选项
  • 选择 dwm 作为窗口管理器的 4 大理由分析

    导读 我喜欢极简 如果可能 我会尽量在一个终端下运行所有需要的程序 这避免了一些浮夸的特效占用我的资源或者分散我的注意力 而且 无论怎么调整窗口大小和位置却依旧无法使它们完美地对齐 这也让我感到厌烦 出于对极简化的追求 我喜欢上了 Xfce
  • 14.SpringData-Mongo

    SpringData Mongo Spring data对MongoDB做了支持 使用spring data mongodb可以简化MongoDB的操作 封装了底层的mongodb driver 地址 https spring io pro
  • opencv图像畸变矫正:源码学习

    参考资料 相机标定 4 矫正畸变 undistort 和initUndistortRectifyMap 背景 opencv提供了直接进行畸变矫正的代码 因在项目中需要使用畸变矫正 因此研究一下opencv中畸变矫正的相关接口与代码 便于学习
  • 凸优化学习(六)——一个简单的对偶实例

    注意 本文内容来自于吴恩达老师cs229课堂笔记的中文翻译项目 https github com Kivy CN Stanford CS 229 CN 中的凸优化部分的内容进行翻译学习 2 一个简单的对偶实例 作为对偶的一个简单应用 在本节
  • 最接近的三数之和

    题目描述 给你一个长度为 n 的整数数组 nums 和 一个目标值 target 请你从 nums 中选出三个整数 使它们的和与 target 最接近 返回这三个数的和 假定每组输入只存在恰好一个解 示例 输入 nums 1 2 1 4 t
  • (计算机复试考研)操作系统重点知识梳理

    1 操作系统引论 操作系统 配置在计算机硬件上的第一层软件 是对硬件系统的首次扩充 为用户和应用程序提供一个简单接口 定义 一组能有效组织和管理计算机硬件和软件的资源 合理地对各类作业进行调度 方便用户使用的程序的集合 操作系统的目标 1
  • C++线程池的实现

    池式结构 在计算机体系结构中有许多池式结构 内存池 数据库连接池 请求池 消息队列 对象池等等 池式结构解决的主要问题为缓冲问题 起到的是缓冲区的作 线程池 通过使 线程池 我们可以有效降低多线程操作中任务申请和释放产 的性能消耗 特别是当
  • Android OpenGL ES零基础系列(三):OpenGL ES的渲染管道及VertexShader与FragmentShader

    前言 在前2篇文章中 我们都说到着色器 且在第二篇中正式说到 这着色器只能用在OpenGL ES2 x等可编程管道里面 而在OpenGL ES1 x是不能用的 但我们一直没有说这是为什么 两者有什么区别 那这篇我们就一起来学习下OpenGL
  • react新出来两个钩子函数是什么?和删掉的will系列有什么区别?

    react新旧生命周期的区别 1 新生命周期中去掉了三个will钩子 分别为componentWillMount componentWillReceiveProps componentWillUpdate 2 新生命周期中新增了两个钩子 分
  • DB2数据库-获取表结构异常:[jcc][t4][1065][12306][4.26.14]CharConvertionException ERRORCODE=-4220,SQLSTATE=null

    背景如下 DB2数据库 获取表结构异常 jcc t4 1065 12306 4 26 14 CharConvertionException ERRORCODE 4220 SQLSTATE null 搜索引擎搜索解决办法 官方解决方法 db2
  • Transformer(四)--实现验证:transformer 机器翻译实践

    转载请注明出处 https blog csdn net nocml article details 125711025 本系列传送门 Transformer 一 论文翻译 Attention Is All You Need 中文版 Tran
  • HBase与MapReduce整合:TableMapper与TableReducer部分源码分析

    目录 关于TableMapper和TableReducer TableMapReduceUtil initTableMapperJob initTableReducerJob TableInputFormat TableRecordRead