深入浅出 OkHttp 源码解析及应用实践

作者:vivo 互联网服务器团队- Tie Qinrui

OkHttp 在 Java 和 Android 世界中被广泛使用,深入学习源代码有助于掌握软件特性和提高编程水平。

本文首先从源代码入手简要分析了一个请求发起过程中的核心代码,接着通过流程图和架构图概括地介绍了OkHttp的整体结构,重点分析了拦截器的责任链模式设计,最后列举了OkHttp拦截器在项目中的实际应用。

一、背景介绍

在生产实践中,常常会遇到这样的场景:需要针对某一类 Http 请求做统一的处理,例如在 Header 里添加请求参数或者修改请求响应等等。这类问题的一种比较优雅的解决方案是使用拦截器来对请求和响应做统一处理。

在 Android 和 Java 世界里 OkHttp 凭借其高效性和易用性被广泛使用。作为一款优秀的开源 Http 请求框架,深入了解它的实现原理,可以学习优秀软件的设计和编码经验,帮助我们更好到地使用它的特性,并且有助于特殊场景下的问题排查。本文尝试从源代码出发探究 OkHttp 的基本原理,并列举了一个简单的例子说明拦截器在我们项目中的实际应用。本文源代码基于 OkHttp 3.10.0。

二、OkHttp 基本原理

2.1 从一个请求示例出发

OkHttp 可以用来发送同步或异步的请求,异步请求与同步请求的主要区别在于异步请求会交由线程池来调度请求的执行。使用 OkHttp 发送一个同步请求的代码相当简洁,示例代码如下:

  • 同步 GET 请求示例

// 1.创建OkHttpClient客户端
OkHttpClient client = new OkHttpClient();
public String getSync(String url) throws IOException {
      OkHttpClient client = new OkHttpClient();
      // 2.创建一个Request对象
      Request request = new Request.Builder()
              .url(url)
              .build();
      // 3.创建一个Call对象并调用execute()方法
      try (Response response = client.newCall(request).execute()) {
          return response.body().string();
      }
  }

其中 execute() 方法是请求发起的入口,RealCall 对象的 execute() 方法的源代码如下:

  • RealCall 的 execute() 方法源代码

@Override public Response execute() throws IOException {
  synchronized (this) { // 同步锁定当前对象,将当前对象标记为“已执行”
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
  }
  captureCallStackTrace(); // 捕获调用栈
  eventListener.callStart(this); // 事件监听器记录“调用开始”事件
  try {
    client.dispatcher().executed(this); // 调度器将当前对象放入“运行中”队列
    Response result = getResponseWithInterceptorChain(); // 通过拦截器发起调用并获取响应
    if (result == null) throw new IOException("Canceled");
    return result;
  } catch (IOException e) {
    eventListener.callFailed(this, e); // 异常时记录“调用失败事件”
    throw e;
  } finally {
    client.dispatcher().finished(this); // 将当前对象从“运行中”队列移除
  }
}

execute() 方法首先将当前请求标记为“已执行”,然后会为重试跟踪拦截器添加堆栈追踪信息,接着事件监听器记录“调用开始”事件,调度器将当前对象放入“运行中”队列 ,之后通过拦截器发起调用并获取响应,最后在 finally 块中将当前请求从“运行中”队列移除,异常发生时事件监听器记录“调用失败”事件。其中关键的方法是 getResponseWithInterceptorChain() ,其源代码如下:

Response getResponseWithInterceptorChain() throws IOException {
    // 构建一个全栈的拦截器列表
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
    interceptors.add(retryAndFollowUpInterceptor);
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    interceptors.add(new CacheInterceptor(client.internalCache()));
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());
    }
    interceptors.add(new CallServerInterceptor(forWebSocket));
 
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, ……);
 
    return chain.proceed(originalRequest);
  }

该方法中按照特定的顺序创建了一个有序的拦截器列表,之后使用拦截器列表创建拦截器链并发起proceed() 方法调用。在chain.proceed() 方法中会使用递归的方式将列表中的拦截器串联起来依次对请求对象进行处理。拦截器链的实现是 OkHttp 的一个巧妙所在,在后文我们会用一小节专门讨论。在继续往下分析之前,通过以上的代码片段我们已经大致看到了一个请求发起的整体流程。

2.2 OkHttp 核心执行流程

一个 OkHttp 请求的核心执行过程如以下流程图所示:

图片

图 2-1 OkHttp请求执行流程图

图中各部分的含义和作用如下:

  • OkHttpClient:是整个 OkHttp 的核心管理类,从面向对象的抽象表示上来看它代表了客户端本身,是请求的调用工厂,用来发送请求和读取响应。在大多数情况下这个类应该是被共享的,因为每个 Client 对象持有自己的连接池和线程池。重复创建则会造成在空闲池上的资源浪费。Client对象可以通过默认的无参构造方法创建也可以通过 Builder 创建自定义的 Client 对象。Client 持有的线程池和连接池资源在空闲时可以自动释放无需客户端代码手动释放,在特殊情况下也支持手动释放。

  • Request:一个 Request 对象代表了一个 Http 请求。它包含了请求地址 url,请求方法类型 method ,请求头 headers,请求体 body 等属性,该对象具有的属性普遍使用了 final 关键字来修饰,正如该类的说明文档中所述,当这个类的 body 为空或者 body 本身是不可变对象时,这个类是一个不可变对象。

  • Response:一个 Response 对象代表了一个 Http 响应。这个实例对象是一个不可变对象,只有 responseBody 是一个可以一次性使用的值,其他属性都是不可变的。

  • RealCall:一个 RealCall 对象代表了一个准备好执行的请求调用。它只能被执行一次。同时负责了调度和责任链组织的两大重任。

  • Dispatcher:调度器。它决定了异步调用何时被执行,内部使用 ExecutorService 调度执行,支持自定义 Executor。

  • EventListener:事件监听器。抽象类 EventListener 定义了在一个请求生命周期中记录各种事件的方法,通过监听各种事件,可以用来捕获应用程序 HTTP 请求的执行指标。从而监控 HTTP 调用的频率和性能。

  • Interceptor:拦截器。对应了软件设计模式中的拦截器模式,拦截器可用于改变、增强软件的常规处理流程,该模式的核心特征是对软件系统的改变是透明的和自动的。OkHttp 将整个请求的复杂逻辑拆分成多个独立的拦截器实现,通过责任链的设计模式将它们串联到一起,完成发送请求获取响应结果的过程。

2.3 OkHttp 整体架构

通过进一步阅读 OkHttp 源码,可以看到 OkHttp 是一个分层的结构。软件分层是复杂系统设计的常用手段,通过分层可以将复杂问题划分成规模更小的子问题,分而治之。同时分层的设计也有利于功能的封装和复用。OkHttp 的架构可以分为:应用接口层,协议层,连接层,缓存层,I/O层。不同的拦截器为各个层次的处理提供调用入口,拦截器通过责任链模式串联成拦截器链,从而完成一个Http请求的完整处理流程。如下图所示:

图片

图 2-2 OkHttp架构图(图片来自网络)

2.4 OkHttp 拦截器的种类和作用

OkHttp 的核心功能是通过拦截器来实现的,各种拦截器的作用分别为:

  • client.interceptors:由开发者设置的拦截器,会在所有的拦截器处理之前进行最早的拦截处理,可用于添加一些公共参数,如自定义 header、自定义 log 等等。

  • RetryAndFollowUpInterceptor:主要负责进行重试和重定向的处理。

  • BridgeInterceptor:主要负责请求和响应的转换。把用户构造的 request 对象转换成发送到服务器 request对象,并把服务器返回的响应转换为对用户友好的响应。

  • CacheInterceptor:主要负责缓存的相关处理,将 Http 的请求结果放到到缓存中,以便在下次进行相同的请求时,直接从缓存中读取结果,提高响应速度。

  • ConnectInterceptor:主要负责建立连接,建立 TCP 连接或者 TLS 连接。

  • client.networkInterceptors:由开发者设置的拦截器,本质上和第一个拦截器类似,但是由于位置不同,所以用处也不同。

  • CallServerInterceptor:主要负责网络数据的请求和响应,也就是实际的网络I/O操作。将请求头与请求体发送给服务器,以及解析服务器返回的 response。

除了框架提供的拦截器外,OkHttp 支持用户自定义拦截器来对请求做增强处理,自定义拦截器可以分为两类,分别是应用程序拦截器和网络拦截器,他们发挥作用的层次结构如下图:

图片

图 2-3 拦截器(图片来自OkHttp官网)

 

不同的拦截器有不同的适用场景,他们各自的优缺点如下:

 

应用程序拦截器

  • 无需担心重定向和重试等中间响应。

  • 总是被调用一次,即使 HTTP 响应是从缓存中提供的。

  • 可以观察到应用程序的原始请求。不关心 OkHttp 注入的标头。

  • 允许短路而不调用 Chain.proceed()方法。

  • 允许重试并多次调用 Chain.proceed()方法。

  • 可以使用 withConnectTimeout、withReadTimeout、withWriteTimeout 调整呼叫超时。

 

网络拦截器

  • 能够对重定向和重试等中间响应进行操作。

  • 缓存响应不会调用。

  • 可以观察到通过网络传输的原始数据。

  • 可以访问携带请求的链接。

2.5 责任链模式串联拦截器调用

OkHttp 内置了 5 个核心的拦截器用来完成请求生命周期中的关键处理,同时它也支持添加自定义的拦截器来增强和扩展 Http 客户端,这些拦截器通过责任链模式串联起来,使得的请求可以在不同拦截器之间流转和处理。

2.5.1 责任链模式

责任链模式 是一种行为设计模式, 允许将请求沿着处理者链发送。 收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下一个处理者。

图片

图 2-4 责任链(图片来自网络)

适用场景 包括:

  • 当程序需要使用不同方式处理不同种类的请求时

  • 当程序必须按顺序执行多个处理者时

  • 当所需要的处理者及其顺序必须在运行时进行改变时

 

优点

  • 可以控制请求处理的顺序

  • 可对发起操作和执行操作的类进行解耦。

  • 可以在不更改现有代码的情况下在程序中新增处理者。

2.5.2 拦截器的串联

责任链的入口从第一个 RealInterceptorChain 对象的 proceed() 方法调用开始。这个方法的设计非常巧妙,在完整的 proceed() 方法里会做一些更为严谨的校验,去掉这些校验后该方法的核心代码如下:

public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec, RealConnection connection) throws IOException {
    if (index >= interceptors.size()) throw new AssertionError();
 
    // ……  
    // Call the next interceptor in the chain.
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec, connection, index + 1, request, call, eventListener, connectTimeout, readTimeout, writeTimeout);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);
 
    // ……
    return response;
  }

这段代码可以看成三个步骤:

  1. 索引判断。index 初始值为0,它指示了拦截器对象在列表中的索引顺序,每执行一次 proceed 方法该参数自增1,当索引值大于拦截器列表的索引下标时异常退出。

  2. 创建下一个责任链对象。

  3. 按照索引顺序获取一个拦截器,并调用 intercept() 方法。

 

  • 责任链串联

单独看这个方法似乎并不能将所有拦截器都串联起来,串联的关键在于 intercept() 方法,intercept() 方法是实现 interceptor 接口时必须要实现的方法,该方法持有下一个责任链 对象 chain,在拦截器的实现类里只需要在 intercept() 方法里的适当地方再次调用 chain.proceed() 方法,程序指令便会重新回到以上代码片段,于是就可以触发对于下一个拦截器的查找和调用了,在这个过程中拦截器对象在列表中的先后顺序非常重要,因为拦截器的调用顺序就是其在列表中的索引顺序。

 

  • 递归方法

从另一个角度来看,proceed() 方法可以看成是一个递归方法。递归方法的基本定义为“函数的定义中调用函数自身”,虽然 proceed() 方法没有直接调用自身,但是除了最后一个拦截器以外,拦截器链中的其他拦截器都会在适当的位置调用 chain.proceed() 方法,责任链对象和拦截器对象合在一起则组成了一个自己调用自己的逻辑循环。按照笔者个人理解,这也是为什么源代码里 Chain 接口被设计成 Interceptor 接口的内部接口,在理解这段代码的时候要把它们两个接口当成一个整体来看,从这样的角度看的话,这样的接口设计是符合“高内聚”的原则的。

 

拦截器 interceptor 和责任链 chain 的关系如下图:

图片

图 2-5 Interceptor 和 Chain 的关系图

三、OkHttp 拦截器在项目中的应用

在我们的项目中,有一类请求需要在请求头 Header 中添加认证信息,使用拦截器来实现可以极大地简化代码,提高代码可读性和可维护性。核心代码只需要实现符合业务需要的拦截器如下:

  • 添加请求头的拦截器

public class EncryptInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request originRequest = chain.request();
 
        // 计算认证信息
        String authorization = this.encrypt(originRequest);
         
        // 添加请求头
        Request request = originRequest.newBuilder()
                .addHeader("Authorization", authorization)
                .build();
        // 向责任链后面传递
        return chain.proceed(request);
    }
}

之后在创建 OkHttpClient 客户端的时候,使用 addInterceptor() 方法将我们的拦截器注册成应用程序拦截器,即可实现自动地、无感地向请求头中添加实时的认证信息的功能。

  • 注册应用程序拦截器

OkHttpClient client = new OkHttpClient.Builder()
    .addInterceptor(new EncryptInterceptor())
    .build();

四、回顾总结

OkHttp 在 Java 和 Android 世界中被广泛使用,通过使用 OkHttp 拦截器可以解决一类问题——针对一类请求统一修改请求或响应内容。深入了解 OkHttp 的设计和实现不仅可以帮助我们学习优秀开源软件的设计和编码经验,也有利于更好地使用软件特性以及对特殊场景下问题的排查。本文尝试从一个同步 GET 请求的例子开始,首先通过源代码片段简要分析了一个请求发起过程中涉及的核心代码,接着用流程图的形式总结了请求执行过程,然后用架构图展示了OkHttp的分层设计,介绍了各种拦截器的用途、工作层次及优缺点,之后着重分析了拦截器的责任链模式设计——本质是一个递归调用,最后用一个简单的例子介绍了 OkHttp 拦截器在实际生产场景中的应用。

 

参考:

  1. OkHttp官方文档

  2. OkHttp源码解析系列文章

分享 vivo 互联网技术干货与沙龙活动,推荐最新行业动态与热门会议。
本文转载于网络 如有侵权请联系删除

相关文章

  • 富勒:石化行业升级中的仓储管理系统应用——访上海富勒信息科技有限公司副总裁张竑伟

    专题目录(主持人/江宏)中国石化企业仓储中国石化企业仓储物流升级进入快车道物流升级进入快车道(作者为中国石化工程建设有限公司专业副总崔悦)物流仓储技术在石化行业的应用及发展(作者为北京起重运输机械设计研究院有限公司物流仓储工程事业部副总汝继星)镇海石化:持续探索物流智能化升级扬子石化:为包装与仓储物流插上“智能化”翅膀——访中国石化扬子石油化工有限公司塑料厂技改办主任高星浙江恒逸石化的物流建设与发展今天国际:助石化产业物流数智化升级——访深圳市今天国际物流技术股份有限公司副总裁梁建平、工程总监程飞 台朔重工:石化行业仓储物流系统建设需求及升级方向——访台朔重工(宁波)有限公司自动化处技术主管顾海峰国自:智能搬运系统助力石化企业优化仓储运营——访浙江国自机器人技术股份有限公司副总裁王文斐富勒:石化行业升级中的仓储管理系统应用——访上海富勒信息科技有限公司副总裁张竑伟近年来,石化行业数字化、智能化转型升级加速,通过更精细、更协同的管理来实现降能耗、增效益,成为石化企业的必然选择。在这一过程中,越来越多的石化企业尝试应用WMS系统实现仓储管理的精细化、智能化、协同化。小虎岛石化物流项目进入“

  • ESLint 插件规则编写的正确打开方式

    ESLint插件规则编写的正确打开方式1.ESLint安装和配置ESLint是⼀个开源的代码静态分析修复⼯具cli,解析代码为AST使用的是espree解析器,该解析器最初是从经典的esprima解析器中fork出来的,但是现在基于另一个媲美esprima的新轮子acorn,同时,@babel/parser也是基于acorn解析器的。首先安装eslint:$npminit $npmieslint-D#安装eslint $npmcreate@eslint/config#初始化eslint配置⽂件复制⽣成的配置⽂件如下:module.exports={ //当前可以使用哪个环境的全局变量 env:{ browser:true,//浏览器环境document es2021:true,//ECMAScript语法Promise node:true,//node环境require }, //extends和plugins的区别:extends=plugin+rule extends:[ 'eslint:recommended', ], parserOptions:{ ecma

  • 图表4 饼图(2)

    选中效果selectedMode:‘multiple’选中模式,表示是否支持多个选中,默认关闭,支持布尔值和字符串,字符串取值可选‘single’,‘multiple’,分别表示单选还是多选selectedOffset:30选中扇区的偏移距离varoption={ series:[{ type:'pie', data:pieData, selectedMode:'multiple',// selectedOffset:30 }] } 复制圆环radius饼图的半径。可以为如下类型:number:直接指定外半径值。string:例如,‘20%’,表示外半径为可视区尺寸(容器高宽中较小一项)的20%长度。Array.:数组的第一项是内半径,第二项是外半径,通过Array,可以将饼图设置为圆环图varoption={ series:[{ type:'pie', data:pieData, radius:['50%','70%'] }] } 复制3.饼图的特点饼图可以很好地帮助用户快速了解不同分

  • 014. Netty 职责链 Pipeline 详解

    1.设计模式-责任链模式1.概念讲解责任链模式(ChainofResponsibilityPattern)为请求创建了一个处理对象的链。 发起请求和具体处理请求的过程解耦:职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无需关心请求的处理细节和请求的传递。 2.实现责任链模式实现责任链模式4个要素:处理器抽象类、具体的处理器实现类、保存处理器信息、处理执行。3.责任链代码演示//---链表形式调用---netty就是类似的这种形式 publicclassPipelineDemo{ /** *初始化的时候造一个head,作为责任链的开始,但是并没有具体处理 */ publicHandlerChainContexthead=newHandlerChainContext(newAbstractHandler(){ @Override voiddoHandler(HandlerChainContexthandlerChanContext,Objectarg0){ handlerChanContext.runNext(arg0); } }); publicvoidaddLas

  • 百度万亿流量转发引擎BFE VS Nginx

    BFE(BaiduFrontEnd,百度统一前端)是百度的统一七层流量转发平台。BFE平台目前已接入百度大部分流量,每日转发请求接近1万亿,峰值QPS超过1000万。在2019年百度春晚红包活动中,BFE平台在超大用户压力、数次流量波峰下平稳运行,保证了春晚红包活动的顺利进行。作为综合的流量转发平台,BFE平台集成了以下4大功能:流量接入和转发:支持HTTP、HTTPS、HTTP/2、QUIC等多种协议,并支持强大的应用层路由能力流量全局调度:支持由外网流量调度和内网流量调度共同构成的全局调度系统安全和防攻击:支持黑名单封禁、精细限流和应用层防火墙(WAF)等多种防攻击能力实时数据分析:支持分钟级的超高维度时序报表作为BFE平台的核心组件,BFE转发引擎从2012年开始研发,并于2014年使用Go语言完成重构。由于基于Go语言,和业界普遍使用的Nginx开源软件相比,BFE具有以下优势:研发效率高:Go语言的开发效率远高于C语言(及Lua),在代码的可维护性方面也有巨大优势。系统的安全和稳定性高:Go语言没有C语言固有的缓冲区溢出隐患,规避了大量的稳定性和安全风险;另外对于异常可以捕捉

  • 什么是SAP CRM里的用户状态(user status)

    CreatedbyJerryWangonFeb19,2016(1)defineanewuserstatusprofileincustomizingbelow:(2)maintainthestatustransitionrelationship.Theexamplebelowdefinesthefollowingstatetransition:a.CreatedstatuscouldonlynavigatetoInprocessstatus,sinceitshighestrangeis20(Inprocess). b.InprocessstatuscouldnavigatetoActivated(30)orClosed(40),howeveritcouldnotreturntoCreated(10)anymore. c.ActivatedstatuscouldnavigatetoInprocessorClosed. d.AfteraproductissettoClosed,itcouldneverbesettoanyotheruserdefinedstatus.Mark“Productm

  • 如何将数据中心10G/25G网络升级至40G/100G 2019-03-28 10:26

    随着云计算、大数据、物联网、人工智能、5G等新兴技术的迅速推广和应用普及,不断涌入的数据流量促使各大服务商不断地重新审视数据中心内数据传输速度的升级。数据中心传输设备需要将数据传输速度从原来的10Gbps、25Gbps提升至40Gbps、100Gbps甚至400Gbps。而由于更高速的光互联网必然带来成本、功耗、尺寸等各方面的挑战,作为数据中心的系统架构师必须谨慎考虑,以确保做出最佳组合选择,特别是减少故障率,减少耗能、提升兼容性等等,从而充分发挥硬件升级带来的各项性能的提升。晟科公司从物理连接方面提出10Gbps/25Gbps提升至40G/100Gps升级方案:解决方案1:40G/100GQSFP转10G/25G4SFP+无源铜芯高速分支线缆:40G/100GQSFP转10G/25G4SFP+无源铜芯高速分支线缆的一端连接一台交换机的40G/100GQSFP端口,另一端连接一台交换机的4个10G/25GSFP+端口,是实现短距离10G/25G到40G/100G传输的经济高效的方法。解决方案2:40/100GQSFP转10G/25G4SFP+有源分支线缆:40G/100GQSFP转10

  • 商城项目-根据用户名和密码查询用户

    7.根据用户名和密码查询用户7.1.接口说明功能说明查询功能,根据参数中的用户名和密码查询指定用户接口路径GET/query复制参数说明:form表单格式参数说明是否必须数据类型默认值username用户名,格式为4~30位字母、数字、下划线是String无password用户密码,格式为4~30位字母、数字、下划线是String无返回结果:用户的json格式数据{ "id":6572312, "username":"test", "phone":"13688886666", "created":1342432424 }复制状态码:200:注册成功400:用户名或密码错误500:服务器内部异常,注册失败7.2.controller/** *根据用户名和密码查询用户 *@paramusername *@parampassword *@return */ @GetMapping("query") publicResponseEntity<User

  • #python# 成语接龙(一)

    本来想写一个机器人成语接龙的,太复杂了,弄一个可以找到所有的可以“一招制敌”的成语,就是没办法再被接龙的成语。第一步是找一个带拼音的成语字库,网上找了半天,没找到合适的,发现搜狗输入法自带成语词库,就拿来解析了。搜狗的字库是scel格式,内容包括拼音表和字库两部分,它们的结构如下所示:解析代码如下[parse_scel.py]:为了避开烦人的字符编码问题,用的是python3增加了print,方便跟踪结果#encoding=utf8 #python3 importsysimportstructPIN_YIN_TAG_LEN=4 defget_hanzi_offset(buff): mask=buff[4] return0x2628ifmask==0x44else0x26c4ifmask==0x45elseNone defget_pinyin_offset(buff): offset=0x1540 returnoffsetifbuff[offset:offset+PIN_YIN_TAG_LEN]==b"\x9d\x01\x00\x00"elseNone def

  • 解决QProcess使用setProcessEnvironment环境变量不能生效的问题

    使用QProcess运行进程时,为了方便使用运行程序,直接使用程序名字运行。但是这时候需要设置环境变量。可是使用setProcessEnvironment怎么设置也不能设置成功。运行QProcess却是一直返回'文件找不到'的现象。下面让我们来窥探究竟吧。不能正确使用环境变量的代码QProcess*myProcess=newQProcess(this); QProcessEnvironmentenv=QProcessEnvironment::systemEnvironment(); env.insert("PATH","C:/AppPath;"+env.value("PATH")); myProcess->setProcessEnvironment(env); myProcess->start("App.exe");复制可以正确设置环境变量的代码QProcess*myProcess=newQProcess(this); QStringpath="C:/AppPath

  • AI一分钟 | 娃哈哈要造智能汽车?世界顶级机器学习科学家黄恒加盟京东

    ▌娃哈哈成立科技创新中心,经营范围包括新能源汽车 9月6日下午消息,根据国家企业信用信息公示系统资最新工商资料显示,娃哈哈于8月27日成立了浙江德清娃哈哈科技创新中心有限公司,注册资本为5000万元,宗庆后担任法人代表。该公司的经营范围包括新一代信息技术、传感技术、先进装备制造技术、新能源汽车及汽车智能技术、新材料、节能环保材料、生物工程、生物医药、医疗器械的技术开发、技术咨询、技术服务、技术转让,企业管理咨询。(via.新浪科技)▌世界顶级机器学习科学家黄恒出任京东大数据首席科学家京东集团昨日(9月6日)宣布,美国匹兹堡大学JohnA.Jurenko杰出冠名讲席教授黄恒博士加入京东。据悉,黄恒教授将加入位于硅谷的京东大数据与智能供应链事业部研发中心,担任京东大数据首席科学家,他的工作重点将聚焦于京东大数据平台上的机器学习平台和深度学习平台研发、优化模型与算法中心及学术研究相关内容。黄恒教授在机器学习、人工智能、大数据、计算机视觉等多学科交叉领域有重要的全球学术影响力,取得了大量令人瞩目的研究成果。过去十年里他发表的计算机顶级会议文章数量,在世界公认的csrankings.org(C

  • C语言基础 - 实现动态数组并增加内存管理

    写在前面 弄了下个人站...防止内容再次被锁定...所有东西都在这里面 welcome~ 个人博客 用C语言实现一个动态数组,并对外暴露出对数组的增、删、改、查函数 (可以存储任意类型的元素并实现内存管理)这里我的编译器就是xcode分析: 模拟存放一个People类有2个属性字符串类型:姓名整型:年龄 array结构体应当有数组长度:length空间:capacity存储对象:value(任意类型) 构造一个任意对象类.拥有retainCount属性.为内存计数器 使用一次retainCount+1,当retainCount为0时释放该对象指向的内存 贴出部分代码 //Object.h #ifndefObject_h #defineObject_h #include<stdio> //定义结构体 typedefstructObject{ intretainCount; }Object; //宏定义方法方便书写 #defineOBJECTRETAIN(obj)objectRetain((Object*)obj) #defineOBJECTRELEASE(obj)object

  • 60万人才储备, 谷歌收购 Kaggle 背后利益分析

    【新智元导读】Kaggle是一个预测建模和机器学习竞赛的众包平台,Google收购Kaggle令它得以在这个人才紧缺的市场获得60万数据科学家的人才储备。Google声称这笔交易将帮助它实现“AI民主化”。如果你是一家试图在AI技术的军备竞赛中巩固地位的公司,不如考虑利用数以千计的数据科学家来增强你的数字产品和服务。这正是谷歌上周收购众包机器学习竞赛平台Kaggle达到的目的。约有60万专业的数据科学家使用Kaggle为诸如癌症检测和心脏病诊断等棘手的挑战建立预测模型。专家认为,Kaggle可以帮助Google推动AI技术更广泛的采用。奇点大学人工智能和机器人学部门负责人NeularJacobstein说:“数据科学和机器学习在现在已经是全球性的,谷歌认识到世界上大多数最聪明的人都在为其他人工作。我认为这可能是非常积极的事情,可以让每个人都更具竞争力。”GoogleCloud人工智能和机器学习首席科学家李飞飞上周在谷歌云大会上宣布,Kaggle团队将与谷歌其他AI团队结合,例如开源机器学习平台TensorFlow。在过去十年里,计算系统变得越来越强大,企业能够收集到大量的数据。尽管用来

  • 微信小程序再次深夜放大招!竟然可以玩起直播来了?

    12月26日,沉寂已久的微信小程序又在深夜搞事情了,这次竟然一下子向我们发射了四大新能力,网友纷纷评论:小程序实属很强势!看到微信官方消息说,两个小程序支持直播,也就是说你可以开发直播小程序了,但是有一些限制,下面具体聊聊小程序直播的内容。一、小程序直播支持的格式目前小程序支付两种格式直播1)flv格式直播2)rtmp格式直播二、能够开通小程序直播的行业类目由于直播需要资质,并不是每个企业都能够开通小程序直播,微信暂时开放了下面几个行业类目:可以看到开放的类目非常少,如果你不在上面的类目中,就不能开通直播功能,需要想一些办法。三、小程序直播开发要用到的组件和接口想要实现小程序直播,需要小程序的基础库版本在1.7.0以上,使用到最新的两个组件和两个新接口:1)live-pusher组件,主要功能是录制,进行推流。2)live-player组件,主要功能是播放。目前支持视频直播功能的类目有五类:社交、教育、医疗、政务民生、金融二、开放两大硬件连接功能小程序可以搜索周边的Wi-Fi.2.开启HCE模式的NFC接口能力支持将安卓手机模拟成交通卡、诊疗卡等实体智能卡。换句话说就是有了这个能力后,

  • MyCobot六轴机械臂的基本操作(二)

    上一讲我们做ssh和vnc的设置,有小伙伴问设置些有什么用,那么这里我先来解释一下这些功能有什么用处,首先我们可以通过ssh在我们的Windows桌面进行程序开发,然后上传到树莓派进行验证,我们也可以在windows平台通过vnc远程操作我们的机械臂,这样你就可以在自己的工作台上自由编程和上网查资料,然后MyCobot他不会占用你的显示器。当然了,你也可以直接拿这个树莓派当做开发机器使用,也是没有问题了。 在这里我们使用pycharm的社区版(Community)就可以了,python的开发工具很多,也可使用notepad++、jupyter、VSCode等,随便你方便就行。这里我们主要使用notepad++和pycharm来做为我们本次教学的编程软件进行讲解。Myblockly这个软件是机械臂树莓派里自带的一种开发工具,有兴趣的小伙伴可以自己试一下。好啦我们开始进入到机械臂的基本操作一:机械臂的校准MyCobot机械在使用前要进行一次校准,这样我们做实验时才能得到正确的结果,那么MyCobot机械臂如何校准呢?(1)在桌面双击rasp_mycobot_test_gui.py,弹出右侧

  • 趣味算法-01-跟着作者读《趣味算法(第2版)》上

    14天阅读挑战赛系列博客:趣味算法-01-跟着作者读《趣味算法(第2版)》上 趣味算法-02-跟着作者读《趣味算法(第2版)》下 趣味算法-03-跟着作者读《趣味算法(第2版)》-算法之美 趣味算法-04-跟着作者读《趣味算法(第2版)》-贪心算法本系列博客主要阅读《趣味算法(第2版)》时的所听所想所感,如果有一起阅读的,可以留言分享。1.《趣学算法(第2版)》书籍简介趣学算法(第2版)由陈小玉著。本书通过趣味故事引出算法问题,分析算法本质,并给出代码实现的详细过程和运行结果,50多个实例及海量图解,随书附赠丰富教学资源,被评为十四五规划教材,同时本书还符合工程教育认证,实用性也很佳。附上教材的封面: 而且还有繁体等多种版本的发行,通过这些就能看出来,陈老师的这本书的确是名副其实。如果没有看的同学,可以放心购买,但购买前最后可以有异步图书的券,比如我大概是通过券+50RMB的价格买到了图书。2.如何读这本书本书图例丰富,按照陈老师说的,她的书一贯都是图例丰富,阅读体验极佳。 《趣学算法(第2版)》这本书一共分为8章:第1章:算法引入,复杂度的计算方法 第2~7章:经典算法,包括贪心算法

  • kubernetes 存储

    EmptyDir ,是一个空目录,他的生命周期和所属的Pod完全一致,可以在同意Pod内的不同容器之间共享工作过程中产生的文件。缺省情况下,使用主机磁盘进行存储。 HostPath一般和DaemonSet搭配使用 PV和PVC管理员创建一系列的PV提供存储,然后为应用提供PVC,应用程序仅需加载一个PVC就可以访问 仰望星空,开怀大笑

  • linux后台不挂断运行 nohup命令

    //后台常在 退出终端仍然运行 nohuppythonpyredis.py&    nohup输出重定向到my.log nohupcommand>my.log2>&1&

  • 静态库和动态库的编译链接和使用

    前言 在编写代码时我们经常会用到第三方提供的函数接口,这些函数一般是以库的形式提供的,常见的库有两种形式,静态库和动态库。 静态库与动态库 在介绍库之前,先简单介绍一下目标文件。目标文件常常按照特定格式来组织,在linux下,它是ELF格式(ExecutableLinkableFormat,可执行可链接格式),而在windows下是PE(PortableExecutable,可移植可执行)。 而通常目标文件有三种形式: 可执行目标文件。即我们通常所认识的,可直接运行的二进制文件。 可重定位目标文件。包含了二进制的代码和数据,可以与其他可重定位目标文件合并,并创建一个可执行目标文件-一般为.o文件。 共享目标文件。它是一种在加载或者运行时进行链接的特殊可重定位目标文件-一般为.so文件。 静态库 将上述提到的可重定位目标文件打包成一个单独的文件(一般为.a文件),这个.a文件就成为静态库。其实静态库就是.o文件的集合,使用ar打包命令来生成静态库。eg.arrcsmylib.a1.o2.o3.o 链接过程 ld最基本的链接单位是.o文件,ld链接器主要解析object文件内的以下内容

  • 语法框架

    学语法就是为了造句,而语法的核心就是动词,造一个句子要看动词用什么,从动词来分析句子结构,了解句子需要哪些成分,从而造句子。 英语最基本的句子 什么怎么样 什么就是主语,主语一般指人或物 怎么样就是谓语,谓语指的是发生了什么事 英语句子拆分到不能再拆分的句子就是最基本的句子即简单句, 英语的语法核心就是动词, 动词为谓语动词和非谓语动词, 一个简单句里面只能有一个谓语动词,谓语动词和非谓语动词可以共存。 下面是用谓语动词造句 有五种动作(动词) 1.可以独立完成的动作,无承受者:不及物动词 PapaRabbitsleeps.兔老爹睡觉。 句子成分:“PapaRabbit”是主语,“sleeps”是谓语动词(不及物动词)。 句子结构:主语+谓语动词(不及物) 2.有一个动词的承受者:单及物动词 PapaRabbitlikesyou.兔老爹喜欢你。 句子成分:“PapaRabbit”是主语,“likes”是谓语动词(单及物动词),“you”是宾语。 句子结构:主语+谓语动词(单及物)+宾语 3.有两个动作承受者:双及物动词 PapaRabbitteachesyouEnglish.兔老爹教

  • 数据库结构整理总结

       近期在做一个ERP数据库结构的梳理。该ERP系统系统有十多个子系统。本次借用powerdesigner工具进行梳理。    梳理过程: 将整体系统按照子系统和组件进行切割。当然也顺便出个组件图。 构建表关系图。 为表名和字段增加中文说明.目标:为表字段的comment增加说明。方法:使用原有的字典表作为源,运行附件中的UpdateDescr_TableName.sql和 UpdateDescr_ColumnName.sql。为方便各子系统分别梳理,需要调整取表的部分。 将需要的表导入powerdesigner的PhysicalData模型中。方法: Database->UpdateModefromDatabase->配置一个ODBC数据源->选择需要的表. 使用脚本将备注中的中文名称导入powerdesigner中的表字段的中文名称中。方法:Tools->ExecuteCommands->Edit/RunScript.打开附件中的TableCommontToName.vbs和

相关推荐

推荐阅读