flink scala 实现不带async I/O驱动的组件交互

flink async 实现

 

主要解决两个问题

1. 如果需要scala实现flink的异步调用,请参考代码

2. 如果要异步调用的组件,并没有提供async I/O的驱动,那么请参考代码

3. (非主要)对异步调用的线程池有兴趣,可以讨论以下

废话不多说,直接上code

package com.test

import java.util.Collections
import java.util.concurrent.{Executors, TimeUnit}

import org.apache.flink.calcite.shaded.com.google.common.util.concurrent.MoreExecutors

//import org.apache.flink.runtime.concurrent.Executors
import org.apache.flink.streaming.api.datastream.AsyncDataStream
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment
import org.apache.flink.streaming.api.functions.async.{AsyncFunction, ResultFuture}

import scala.concurrent.{ExecutionContext, Future}
import scala.util.{Failure, Success}

/**
 * @author johnCai
 * @date 2021/4/27 下午10:03
 * @version 1.0
 */
object AsyncTest {
  def main(args: Array[String]): Unit = {
    val env = StreamExecutionEnvironment.getExecutionEnvironment
    //注意这个地方,下边统称A处
    env.setParallelism(2)
    val ds = env.socketTextStream("localhost",2222)
    AsyncDataStream
      .unorderedWait(ds,new AsyncRequest,8000, TimeUnit.MICROSECONDS,100)
      .print("out put: ")
    env.execute("async")
  }
}


class AsyncRequest extends AsyncFunction[String,String] {
  var i = 0
  //第一种方式
  //implicit lazy val executor: ExecutionContext = ExecutionContext.fromExecutor(Executors.directExecutor())
  //第二中方式
  implicit lazy val executor: ExecutionContext = ExecutionContext.fromExecutor(MoreExecutors.directExecutor())
  //第三种方式(不可行)
  //implicit lazy val executor: ExecutionContext = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(10))
  override def asyncInvoke(input: String, resultFuture: ResultFuture[String]): Unit = {
    val f = Future {
      i+=1
      val str = "result_"+i
      println(s"in async recv $str")
      Thread sleep 2000
      str
    }

    f onComplete {
      case Success(value) =>
        println(s"in async send ${value}")
        resultFuture.complete(Collections.singletonList(value))
      case Failure(exception) => exception.printStackTrace()

    }
  }
}

flink官方文档摘录

实现提示 #

在实现使用 Executor(或者 Scala 中的 ExecutionContext)和回调的 Futures 时,建议使用 DirectExecutor,因为通常回调的工作量很小,DirectExecutor 避免了额外的线程切换开销。回调通常只是把结果发送给 ResultFuture,也就是把它添加进输出缓冲。从这里开始,包括发送记录和与 chenkpoint 交互在内的繁重逻辑都将在专有的线程池中进行处理。

DirectExecutor 可以通过 org.apache.flink.runtime.concurrent.Executors.directExecutor() 或 com.google.common.util.concurrent.MoreExecutors.directExecutor() 获得。

警告 #

Flink 不以多线程方式调用 AsyncFunction

我们想在这里明确指出一个经常混淆的地方:AsyncFunction 不是以多线程方式调用的。 只有一个 AsyncFunction 实例,它被流中相应分区内的每个记录顺序地调用。除非 asyncInvoke(...) 方法快速返回并且依赖于(客户端的)回调, 否则无法实现正确的异步 I/O。

例如,以下情况导致阻塞的 asyncInvoke(...) 函数,从而使异步行为无效:

  • 使用同步数据库客户端,它的查询方法调用在返回结果前一直被阻塞。
  • 在 asyncInvoke(...) 方法内阻塞等待异步客户端返回的 future 类型对象

大概就是这么个意思了,如果用 org.apache.flink.runtime.concurrent.Executors.directExecutor() 或 com.google.common.util.concurrent.MoreExecutors.directExecutor() 获得的executors,没有指定线程池大小,所以它的并行度是按代码A处(也就是flink设置的并行度,或者flink executor的线程池了),应为如果将flink的并行度设置为1,经测试完全串行,方法一和方法二等价

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值