快速灵敏的Flink2

news2024/11/25 19:49:26

flink基础知识

TumblingEventTimeWindows 滚动开窗

package org.apache.flink.streaming.api.windowing.assigners;

import org.apache.flink.annotation.PublicEvolving;
import org.apache.flink.api.common.ExecutionConfig;
import org.apache.flink.api.common.typeutils.TypeSerializer;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.streaming.api.windowing.triggers.EventTimeTrigger;
import org.apache.flink.streaming.api.windowing.triggers.Trigger;
import org.apache.flink.streaming.api.windowing.windows.TimeWindow;

import java.util.Collection;
import java.util.Collections;

/**
 * A {@link WindowAssigner} that windows elements into windows based on the timestamp of the
 * elements. Windows cannot overlap.
 *
 * <p>For example, in order to window into windows of 1 minute:
 *
 * <pre>{@code
 * DataStream<Tuple2<String, Integer>> in = ...;
 * KeyedStream<Tuple2<String, Integer>, String> keyed = in.keyBy(...);
 * WindowedStream<Tuple2<String, Integer>, String, TimeWindow> windowed =
 *   keyed.window(TumblingEventTimeWindows.of(Time.minutes(1)));
 * }</pre>
 */
@PublicEvolving
public class TumblingEventTimeWindows extends WindowAssigner<Object, TimeWindow> {
    private static final long serialVersionUID = 1L;

    private final long size;

    private final long globalOffset;

    private Long staggerOffset = null;

    private final WindowStagger windowStagger;

    protected TumblingEventTimeWindows(long size, long offset, WindowStagger windowStagger) {
        if (Math.abs(offset) >= size) {
            throw new IllegalArgumentException(
                    "TumblingEventTimeWindows parameters must satisfy abs(offset) < size");
        }

        this.size = size;
        this.globalOffset = offset;
        this.windowStagger = windowStagger;
    }

    @Override
    public Collection<TimeWindow> assignWindows(
            Object element, long timestamp, WindowAssignerContext context) {
        if (timestamp > Long.MIN_VALUE) {
            if (staggerOffset == null) {
                staggerOffset =
                        windowStagger.getStaggerOffset(context.getCurrentProcessingTime(), size);
            }
            // Long.MIN_VALUE is currently assigned when no timestamp is present
            long start =
                    TimeWindow.getWindowStartWithOffset(
                            timestamp, (globalOffset + staggerOffset) % size, size);
            return Collections.singletonList(new TimeWindow(start, start + size));
        } else {
            throw new RuntimeException(
                    "Record has Long.MIN_VALUE timestamp (= no timestamp marker). "
                            + "Is the time characteristic set to 'ProcessingTime', or did you forget to call "
                            + "'DataStream.assignTimestampsAndWatermarks(...)'?");
        }
    }

    @Override
    public Trigger<Object, TimeWindow> getDefaultTrigger(StreamExecutionEnvironment env) {
        return EventTimeTrigger.create();
    }

    @Override
    public String toString() {
        return "TumblingEventTimeWindows(" + size + ")";
    }

    /**
     * Creates a new {@code TumblingEventTimeWindows} {@link WindowAssigner} that assigns elements
     * to time windows based on the element timestamp.
     *
     * @param size The size of the generated windows.
     * @return The time policy.
     */
    public static TumblingEventTimeWindows of(Time size) {
        return new TumblingEventTimeWindows(size.toMilliseconds(), 0, WindowStagger.ALIGNED);
    }

    /**
     * Creates a new {@code TumblingEventTimeWindows} {@link WindowAssigner} that assigns elements
     * to time windows based on the element timestamp and offset.
     *
     * <p>For example, if you want window a stream by hour,but window begins at the 15th minutes of
     * each hour, you can use {@code of(Time.hours(1),Time.minutes(15))},then you will get time
     * windows start at 0:15:00,1:15:00,2:15:00,etc.
     *
     * <p>Rather than that,if you are living in somewhere which is not using UTC±00:00 time, such as
     * China which is using UTC+08:00,and you want a time window with size of one day, and window
     * begins at every 00:00:00 of local time,you may use {@code of(Time.days(1),Time.hours(-8))}.
     * The parameter of offset is {@code Time.hours(-8))} since UTC+08:00 is 8 hours earlier than
     * UTC time.
     *
     * @param size The size of the generated windows.
     * @param offset The offset which window start would be shifted by.
     */
    public static TumblingEventTimeWindows of(Time size, Time offset) {
        return new TumblingEventTimeWindows(
                size.toMilliseconds(), offset.toMilliseconds(), WindowStagger.ALIGNED);
    }

    /**
     * Creates a new {@code TumblingEventTimeWindows} {@link WindowAssigner} that assigns elements
     * to time windows based on the element timestamp, offset and a staggering offset, depending on
     * the staggering policy.
     *
     * @param size The size of the generated windows.
     * @param offset The globalOffset which window start would be shifted by.
     * @param windowStagger The utility that produces staggering offset in runtime.
     */
    @PublicEvolving
    public static TumblingEventTimeWindows of(Time size, Time offset, WindowStagger windowStagger) {
        return new TumblingEventTimeWindows(
                size.toMilliseconds(), offset.toMilliseconds(), windowStagger);
    }

    @Override
    public TypeSerializer<TimeWindow> getWindowSerializer(ExecutionConfig executionConfig) {
        return new TimeWindow.Serializer();
    }

    @Override
    public boolean isEventTime() {
        return true;
    }
}

SlidingEventTimeWindows 滑动开窗

package org.apache.flink.streaming.api.windowing.assigners;

import org.apache.flink.annotation.PublicEvolving;
import org.apache.flink.api.common.ExecutionConfig;
import org.apache.flink.api.common.typeutils.TypeSerializer;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.streaming.api.windowing.triggers.EventTimeTrigger;
import org.apache.flink.streaming.api.windowing.triggers.Trigger;
import org.apache.flink.streaming.api.windowing.windows.TimeWindow;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * A {@link WindowAssigner} that windows elements into sliding windows based on the timestamp of the
 * elements. Windows can possibly overlap.
 *
 * <p>For example, in order to window into windows of 1 minute, every 10 seconds:
 *
 * <pre>{@code
 * DataStream<Tuple2<String, Integer>> in = ...;
 * KeyedStream<Tuple2<String, Integer>, String> keyed = in.keyBy(...);
 * WindowedStream<Tuple2<String, Integer>, String, TimeWindow> windowed =
 *   keyed.window(SlidingEventTimeWindows.of(Time.minutes(1), Time.seconds(10)));
 * }</pre>
 */
@PublicEvolving
public class SlidingEventTimeWindows extends WindowAssigner<Object, TimeWindow> {
    private static final long serialVersionUID = 1L;

    private final long size;

    private final long slide;

    private final long offset;

    protected SlidingEventTimeWindows(long size, long slide, long offset) {
        if (Math.abs(offset) >= slide || size <= 0) {
            throw new IllegalArgumentException(
                    "SlidingEventTimeWindows parameters must satisfy "
                            + "abs(offset) < slide and size > 0");
        }

        this.size = size;
        this.slide = slide;
        this.offset = offset;
    }

    @Override
    public Collection<TimeWindow> assignWindows(
            Object element, long timestamp, WindowAssignerContext context) {
        if (timestamp > Long.MIN_VALUE) {
            List<TimeWindow> windows = new ArrayList<>((int) (size / slide));
            long lastStart = TimeWindow.getWindowStartWithOffset(timestamp, offset, slide);
            for (long start = lastStart; start > timestamp - size; start -= slide) {
                windows.add(new TimeWindow(start, start + size));
            }
            return windows;
        } else {
            throw new RuntimeException(
                    "Record has Long.MIN_VALUE timestamp (= no timestamp marker). "
                            + "Is the time characteristic set to 'ProcessingTime', or did you forget to call "
                            + "'DataStream.assignTimestampsAndWatermarks(...)'?");
        }
    }

    public long getSize() {
        return size;
    }

    public long getSlide() {
        return slide;
    }

    @Override
    public Trigger<Object, TimeWindow> getDefaultTrigger(StreamExecutionEnvironment env) {
        return EventTimeTrigger.create();
    }

    @Override
    public String toString() {
        return "SlidingEventTimeWindows(" + size + ", " + slide + ")";
    }

    /**
     * Creates a new {@code SlidingEventTimeWindows} {@link WindowAssigner} that assigns elements to
     * sliding time windows based on the element timestamp.
     *
     * @param size The size of the generated windows.
     * @param slide The slide interval of the generated windows.
     * @return The time policy.
     */
    public static SlidingEventTimeWindows of(Time size, Time slide) {
        return new SlidingEventTimeWindows(size.toMilliseconds(), slide.toMilliseconds(), 0);
    }

    /**
     * Creates a new {@code SlidingEventTimeWindows} {@link WindowAssigner} that assigns elements to
     * time windows based on the element timestamp and offset.
     *
     * <p>For example, if you want window a stream by hour,but window begins at the 15th minutes of
     * each hour, you can use {@code of(Time.hours(1),Time.minutes(15))},then you will get time
     * windows start at 0:15:00,1:15:00,2:15:00,etc.
     *
     * <p>Rather than that,if you are living in somewhere which is not using UTC±00:00 time, such as
     * China which is using UTC+08:00,and you want a time window with size of one day, and window
     * begins at every 00:00:00 of local time,you may use {@code of(Time.days(1),Time.hours(-8))}.
     * The parameter of offset is {@code Time.hours(-8))} since UTC+08:00 is 8 hours earlier than
     * UTC time.
     *
     * @param size The size of the generated windows.
     * @param slide The slide interval of the generated windows.
     * @param offset The offset which window start would be shifted by.
     * @return The time policy.
     */
    public static SlidingEventTimeWindows of(Time size, Time slide, Time offset) {
        return new SlidingEventTimeWindows(
                size.toMilliseconds(), slide.toMilliseconds(), offset.toMilliseconds());
    }

    @Override
    public TypeSerializer<TimeWindow> getWindowSerializer(ExecutionConfig executionConfig) {
        return new TimeWindow.Serializer();
    }

    @Override
    public boolean isEventTime() {
        return true;
    }
}

assignTimestampsAndWatermarks 水印

  /**
   * Assigns timestamps to the elements in the data stream and generates watermarks to signal
   * event time progress. The given [[WatermarkStrategy is used to create a [[TimestampAssigner]]
   * and [[org.apache.flink.api.common.eventtime.WatermarkGenerator]].
   *
   * For each event in the data stream, the [[TimestampAssigner#extractTimestamp(Object, long)]]
   * method is called to assign an event timestamp.
   *
   * For each event in the data stream, the
   * [[WatermarkGenerator#onEvent(Object, long, WatermarkOutput)]] will be called.
   *
   * Periodically (defined by the [[ExecutionConfig#getAutoWatermarkInterval()]]), the
   * [[WatermarkGenerator#onPeriodicEmit(WatermarkOutput)]] method will be called.
   *
   * Common watermark generation patterns can be found as static methods in the
   * [[org.apache.flink.api.common.eventtime.WatermarkStrategy]] class.
   */
  def assignTimestampsAndWatermarks(watermarkStrategy: WatermarkStrategy[T]): DataStream[T] = {
    val cleanedStrategy = clean(watermarkStrategy)

    asScalaStream(stream.assignTimestampsAndWatermarks(cleanedStrategy))
  }

allowedLateness 分布式架构

分布式架构,有可能出现数据的乱序,窗口要关闭的时候,数据还没有到,那么窗口等一会再关闭,解决数据的迟到问题。允许处理迟到的数据。

  /**
    * Sets the allowed lateness to a user-specified value.
    * If not explicitly set, the allowed lateness is [[0L]].
    * Setting the allowed lateness is only valid for event-time windows.
    * If a value different than 0 is provided with a processing-time
    * [[org.apache.flink.streaming.api.windowing.assigners.WindowAssigner]],
    * then an exception is thrown.
    */
  @PublicEvolving
  def allowedLateness(lateness: Time): WindowedStream[T, K, W] = {
    javaStream.allowedLateness(lateness)
    this
  }

sideOutputLateData  侧输出流

上面allowedLateness()之后,发现还有没到的,放在侧输出流。将迟到的数据放入侧输出流。

  /**
   * Send late arriving data to the side output identified by the given [[OutputTag]]. Data
   * is considered late after the watermark has passed the end of the window plus the allowed
   * lateness set using [[allowedLateness(Time)]].
   *
   * You can get the stream of late data using [[DataStream.getSideOutput()]] on the [[DataStream]]
   * resulting from the windowed operation with the same [[OutputTag]].
   */
  @PublicEvolving
  def sideOutputLateData(outputTag: OutputTag[T]): WindowedStream[T, K, W] = {
    javaStream.sideOutputLateData(outputTag)
    this
  }

flink实操

(1)

package nj.zb.kb23.api.windows

import java.time.Duration

import nj.zb.kb23.source.SensorReading
import org.apache.flink.api.common.eventtime.{SerializableTimestampAssigner, WatermarkStrategy}
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.scala.function.ProcessWindowFunction
import org.apache.flink.streaming.api.scala.{DataStream, StreamExecutionEnvironment}
import org.apache.flink.streaming.api.windowing.assigners.{SlidingEventTimeWindows, TumblingEventTimeWindows}
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.TimeWindow
import org.apache.flink.util.Collector

object WindowEventTimeTest {
  def main(args: Array[String]): Unit = {
    val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
    env.setParallelism(1)
    val inputStream: DataStream[String] = env.socketTextStream("192.168.91.11", 7777)
    val dataStream: DataStream[SensorReading] = inputStream.map(data => {
      val arr: Array[String] = data.split(",")
      SensorReading(arr(0), arr(1).toLong, arr(2).toDouble)
    })
    //    dataStream.setParallelism()
    //设置以事件时间为时间语意
    val dataStream2: DataStream[SensorReading] = dataStream.assignTimestampsAndWatermarks(
      WatermarkStrategy.forBoundedOutOfOrderness(Duration.ofSeconds((3)))
        .withTimestampAssigner(
          new SerializableTimestampAssigner[SensorReading] {
            override def extractTimestamp(element: SensorReading, recordTimestamp: Long): Long = {
              //指定事件时间的字段
              element.timestamp * 1000
            }
          }
        )
    )
    val lataTag = new OutputTag[SensorReading]("lastdata")
    val windowStream: WindowedStream[SensorReading, String, TimeWindow] = dataStream2.keyBy(_.id)
      .window(TumblingEventTimeWindows.of(Time.seconds(15))) //滚动开窗
//      .window(SlidingEventTimeWindows.of(Time.seconds(15),Time.seconds(3)))//滑动开窗
      .allowedLateness(Time.minutes(1)) //最长延迟一分钟
      .sideOutputLateData(lataTag)//非常非常延迟的数据,放入侧输出流

    /*    val resultStream: DataStream[SensorReading] = windowStream.reduce(
      (curReduce, newReducw) => {
        SensorReading(curReduce.id, curReduce.timestamp, curReduce.temperature.min(newReducw.temperature))
      }
    )*/
   val resultStream: DataStream[SensorReading] = windowStream.process(new MyEventProcessWindowFunction)
    resultStream.print("result:")
    resultStream.getSideOutput(lataTag).print("late value:")//.addSink()
    env.execute("windowEventTime")

  }
}

class MyEventProcessWindowFunction extends ProcessWindowFunction[SensorReading,SensorReading,String,TimeWindow]{
  override def process(
                        key: String,
                        context: Context,
                        elements: Iterable[SensorReading],
                        out: Collector[SensorReading]): Unit = {
    val window: TimeWindow = context.window
    println(window.getStart,window.getEnd)
    val iterator: Iterator[SensorReading] = elements.iterator
    var temp = 100.0
    var timestam = 1
    out.collect(SensorReading(key,timestam,temp))
//    out.collect(SensorReading(key,1,0.0))
  }
}

(2)

package nj.zb.kb23.api.windows

import java.time.Duration

import nj.zb.kb23.source.SensorReading
import org.apache.flink.api.common.eventtime.{SerializableTimestampAssigner, WatermarkStrategy}
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.scala.function.ProcessWindowFunction
import org.apache.flink.streaming.api.scala.{DataStream, StreamExecutionEnvironment}
import org.apache.flink.streaming.api.windowing.assigners.{SlidingEventTimeWindows, TumblingEventTimeWindows}
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.TimeWindow
import org.apache.flink.util.Collector

object WindowEventTimeTest {
  def main(args: Array[String]): Unit = {
    val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
    env.setParallelism(1)
    val inputStream: DataStream[String] = env.socketTextStream("192.168.91.11", 7777)
    val dataStream: DataStream[SensorReading] = inputStream.map(data => {
      val arr: Array[String] = data.split(",")
      SensorReading(arr(0), arr(1).toLong, arr(2).toDouble)
    })
    //    dataStream.setParallelism()
    //设置以时间时间为时间语意
    val dataStream2: DataStream[SensorReading] = dataStream.assignTimestampsAndWatermarks(
      WatermarkStrategy.forBoundedOutOfOrderness(Duration.ofSeconds((3)))
        .withTimestampAssigner(
          new SerializableTimestampAssigner[SensorReading] {
            override def extractTimestamp(element: SensorReading, recordTimestamp: Long): Long = {
              //指定事件时间的字段
              element.timestamp * 1000
            }
          }
        )
    )
    val lataTag = new OutputTag[SensorReading]("lastdata")
    val windowStream: WindowedStream[SensorReading, String, TimeWindow] = dataStream2.keyBy(_.id)
      .window(TumblingEventTimeWindows.of(Time.seconds(15))) //滚动开窗
//      .window(SlidingEventTimeWindows.of(Time.seconds(15),Time.seconds(3)))//滑动开窗
      .allowedLateness(Time.minutes(1)) //最长延迟一分钟
      .sideOutputLateData(lataTag)//非常非常延迟的数据,放入侧输出流

    val resultStream: DataStream[(String, Double, Long, Long)] = windowStream.process(new MyEventProcessWindowFunction)
    resultStream.print("result:")
    resultStream.getSideOutput(lataTag).print("late value:")//.addSink()
    env.execute("windowEventTime")

  }
}
class MyEventProcessWindowFunction extends ProcessWindowFunction[SensorReading,(String,Double,Long,Long),String,TimeWindow]{
  override def process(
                        key: String,
                        context: Context,
                        elements: Iterable[SensorReading],
                        out: Collector[(String, Double, Long, Long)]): Unit = {
    val window: TimeWindow = context.window
    val iterator: Iterator[SensorReading] = elements.iterator
    var temp = 100.0
    var timestam = 1
    while (iterator.hasNext){
      val sensorReading: SensorReading = iterator.next()
      temp = temp.min(sensorReading.temperature)
    }
    out.collect((key,temp,window.getStart,window.getEnd))
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1182983.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

快速了解什么是跳跃表(skip list)

什么是跳跃表&#xff08;skip list&#xff09; 跳跃表&#xff08;Skip List&#xff09;是一种概率性的数据结构&#xff0c;它通过在多层链表的基础上添加“快速通道”来提高搜索效率。跳跃表的效率可以与平衡树相媲美&#xff0c;即在平均和最坏的情况下&#xff0c;查找…

alibaba店铺所有商品数据接口(alibaba.item_search_shop)

阿里巴巴店铺的所有商品数据接口&#xff08;item_search_shop&#xff09;可以获取到店铺内所有商品的信息&#xff0c;包括产品的ID、SKU信息、价格、库存、图片等。这些数据可以用于构建各种业务场景&#xff0c;例如供应链管理、电商平台的价格比较、竞品分析、实时库存查询…

Java练习题一

韩顺平老师的Java练习题 大家可以尝试着做一做 package exer;public class Demo01 {public static void main(String[] args) {double total 100000d;int count0;while(true){if (total > 50000) {total total*0.95;count;}else if (total<50000){total total-1000;co…

最新Next 14快速上手基础部分

最新Next 14快速上手基础部分 最新的NEXT快速上手文档&#xff0c;2023.10.27 英文官网同步&#xff0c;版本Next14.0.0 本项目案例&#xff1a;GitHub地址&#xff0c;可以根据git回滚代码到对应知识&#xff0c;若有错误&#xff0c;欢迎指正&#xff01; 一、介绍 1.什么是…

Flink SQL TopN语句详解

TopN 定义&#xff08;⽀持 Batch\Streaming&#xff09;&#xff1a; TopN 对应离线数仓的 row_number()&#xff0c;使⽤ row_number() 对某⼀个分组的数据进⾏排序。 应⽤场景&#xff1a; 根据 某个排序 条件&#xff0c;计算 某个分组 下的排⾏榜数据。 SQL 语法标准&am…

如何利用JSON Schema校验JSON数据格式

最近笔者在工作中需要监控一批http接口&#xff0c;并对返回的JSON数据进行校验。正好之前在某前端大神的分享中得知这个神器的存在&#xff0c;调研一番之后应用在该项目中&#xff0c;并取得了不错的效果&#xff0c;特地在此分享给各位读者。<br style"box-sizing: …

Moco框架初探

一、简介 Moco是一个搭建模拟服务器的工具&#xff0c;其支持API和独立运行两种方式&#xff0c;前者通常在junit等测试框架中使用&#xff0c;后者则是通过运行一个jar包开启服务。 二、用途 主要用于实现mock技术 1、后端接口开发未完成情况下&#xff0c;通过moco模拟接…

JavaWeb课程复习资料——idea创建JDBC

1、创建空的Java Project 输入项目名称 空项目 2、引入jar包步骤 依次点击 File -> Project Structure&#xff08;快捷键 Ctrl Alt Shift s&#xff09;&#xff0c;点击Project Structure界面左侧的“Modules”如图&#xff1a; 在 【Dependencies】 标签界面下&…

C语言学习笔记之结构篇

C语言是一门结构化程序设计语言。在C语言看来&#xff0c;现实生活中的任何事情都可看作是三大结构或者三大结构的组合的抽象&#xff0c;即顺序&#xff0c;分支&#xff08;选择&#xff09;&#xff0c;循环。 所谓顺序就是一条路走到黑&#xff1b;生活中在很多事情上我们都…

MVCC中的可见性算法

在之前的文章 MVCC详解-CSDN博客中我们已经介绍过了MVCC的原理&#xff08;read viewundo log&#xff09;&#xff0c;今天来详细的说一下readview的匹配规则&#xff08;可见性算法&#xff09; 隔离级别在RC&#xff0c;RR的前提下 Read View是如何保证可见性判断的呢&#…

微服务-grpc

微服务 一、微服务&#xff08;microservices&#xff09; 近几年,微服这个词闯入了我们的视线范围。在百度与谷歌中随便搜一搜也有几千万条的结果。那么&#xff0c;什么是微服务 呢&#xff1f;微服务的概念是怎么产生的呢&#xff1f; 我们就来了解一下Go语言与微服务的千丝…

机器学习——回归

目录 一、线性回归 1、回归的概念&#xff08;Regression、Prediction&#xff09; 2、符号约定 3、算法流程 4、最小二乘法&#xff08;LSM&#xff09; 二、梯度下降 梯度下降的三种形式 1、批量梯度下降&#xff08;Batch Gradient Descent,BGD&#xff09;&#xff…

Unity地面交互效果——4、制作地面凹陷轨迹

大家好&#xff0c;我是阿赵。   上一篇介绍了曲面细分着色器的基本用法和思路&#xff0c;这一篇在曲面细分的基础上&#xff0c;制作地面凹陷的轨迹效果。 一、思路分析 这次需要达到的效果是这样的&#xff1a; 从效果上看&#xff0c;这个凹陷在地面下的轨迹&#xff0…

BigDecimal使用的时候需要注意什么?

BigDecimal只要涉及到浮点数运算都会用到BigDecimal&#xff0c;并且面试的时候经常会问到&#xff0c;那么BigDecimal使用的时候需要注意什么&#xff1f; 目录 1.为什么不能用浮点数表示金额&#xff1f;2.十进制转换二进制3.科学记数法4.IEEE 7545.在线浮点数转换二进制6.原…

Go uuid库介绍

简介&#xff1a; 在现代软件开发中&#xff0c;全球唯一标识符&#xff08;UUID&#xff09;在许多场景中发挥着重要的作用。UUID是一种128位的唯一标识符&#xff0c;它能够保证在全球范围内不重复。在Go语言中&#xff0c;我们可以使用第三方库github.com/google/uuid来方便…

怎样在iOS手机上进行自动化测试

Airtest支持iOS自动化测试&#xff0c;在Mac上为iOS手机部署iOS-Tagent之后&#xff0c;就可以使用AirtestIDE连接设备&#xff0c;像连接安卓设备一样&#xff0c;实时投影、控制手机。iOS测试不仅限于真机测试&#xff0c;iOS模拟器也可以进行。Mac端上部署完成后还可以提供给…

python-re模块

python之正则表达式-基础匹配https://blog.csdn.net/Python_1981/article/details/133777795python之正则表达式-元字符匹配https://blog.csdn.net/Python_1981/article/details/133778805 一、查找 1、findall 2、search 如果没有匹配到&#xff0c;会返回None, 使用group会报…

大文件传输小知识 | UDP和TCP哪个传输速度快?

在网络世界中&#xff0c;好像有两位“传输巨头”常常被提起&#xff1a;UDP和TCP。它们分别代表着用户数据报协议和传输控制协议。那么它们是什么&#xff1f;它们有什么区别&#xff1f;它们在传输大文件时的速度又如何&#xff1f;本文将深度解析这些问题&#xff0c;帮助企…

基于若依的ruoyi-nbcio流程管理系统仿钉钉流程json转bpmn的flowable的xml格式(简单支持发起人与审批人的流程)续

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 之前生产的xml&#xff0c;在bpmn设计里编辑有些内容不正确&#xff0c;包括审批人&#xff0c;关联表单等…

利用python找出偏序集中极大元、极小元、最大元和最小元

1 问题 在离散数学“关系”这一章的学习过程中&#xff0c;学到偏序集中极大元、极小元、最大元和最小元的求解方法&#xff0c;于是提出能不能用python语言实现偏序集中极大元、极小元、最大元和最小元的求解&#xff1f; 2 方法 判断偏序集中的极大元、极小元、最大元和最小元…