国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

聊聊Flink必知必會(huì)(五)

這篇具有很好參考價(jià)值的文章主要介紹了聊聊Flink必知必會(huì)(五)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

  1. 聊聊Flink的必知必會(huì)(三)
  2. 聊聊Flink必知必會(huì)(四)

從源碼中,根據(jù)關(guān)鍵的代碼,梳理一下Flink中的時(shí)間與窗口實(shí)現(xiàn)邏輯。

WindowedStream

對(duì)數(shù)據(jù)流執(zhí)行keyBy()操作后,再調(diào)用window()方法,就會(huì)返回WindowedStream,表示分區(qū)后又加窗的數(shù)據(jù)流。如果數(shù)據(jù)流沒(méi)有經(jīng)過(guò)分區(qū),直接調(diào)用window()方法則會(huì)返回AllWindowedStream。

如下:

// 構(gòu)造函數(shù)
public WindowedStream(KeyedStream<T, K> input, WindowAssigner<? super T, W> windowAssigner) {
    this.input = input;
    this.builder =
    new WindowOperatorBuilder<>(
    windowAssigner,
    windowAssigner.getDefaultTrigger(input.getExecutionEnvironment()),
    input.getExecutionConfig(),
    input.getType(),
    input.getKeySelector(),
    input.getKeyType());
}
        
// KeyedStream類(lèi)型,表示被加窗的輸入流。
private final KeyedStream<T, K> input;

// 用于構(gòu)建WindowOperator,最終會(huì)生成windowAssigner,Evictor,Trigger
private final WindowOperatorBuilder<T, K, W> builder;

在這里面還涉及到一些窗口的基本計(jì)算算子,比如reduce,aggregate,apply,process,sum等等.

窗口相關(guān)模型的實(shí)現(xiàn)

Window

Window類(lèi)是Flink中對(duì)窗口的抽象。它是一個(gè)抽象類(lèi),包含抽象方法maxTimestamp(),用于獲取屬于該窗口的最大時(shí)間戳。

TimeWindow類(lèi)是其子類(lèi)。包含了窗口的start,end,offset等時(shí)間概念字段,這里會(huì)計(jì)算窗口的起始時(shí)間:

// 構(gòu)造函數(shù)
public TimeWindow(long start, long end) {
    this.start = start;
    this.end = end;
}

// timestamp:獲取窗口啟動(dòng)時(shí)的第一個(gè)時(shí)間戳epoch毫秒
public static long getWindowStartWithOffset(long timestamp, long offset, long windowSize) {
    final long remainder = (timestamp - offset) % windowSize;
    // handle both positive and negative cases
    if (remainder < 0) {
        return timestamp - (remainder + windowSize);
    } else {
        return timestamp - remainder;
    }
}

WindowAssigner

WindowAssigner表示窗口分配器,用來(lái)把元素分配到零個(gè)或多個(gè)窗口(Window對(duì)象)中。它是一個(gè)抽象類(lèi),其中重要的抽象方法為assignWindows()方法,用來(lái)給元素分配窗口。

Flink有多種類(lèi)型的窗口,如Tumbling Window、Sliding Window等。各種類(lèi)型的窗口又分為基于事件時(shí)間或處理時(shí)間的窗口。WindowAssigner的實(shí)現(xiàn)類(lèi)就對(duì)應(yīng)著具體類(lèi)型的窗口。

SlidingEventTimeWindows是WindowAssigner的另一個(gè)實(shí)現(xiàn)類(lèi),表示基于事件時(shí)間的Sliding Window。它有3個(gè)long類(lèi)型的字段size、slide和offset,分別表示窗口的大小、滑動(dòng)的步長(zhǎng)和窗口起始位置的偏移量。它對(duì)assignWindows()方法的實(shí)現(xiàn)如下:

@Override
public Collection<TimeWindow> assignWindows(
        Object element, long timestamp, WindowAssignerContext context) {
        // Long.MIN_VALUE is currently assigned when no timestamp is present
    if (timestamp > Long.MIN_VALUE) {
        if (staggerOffset == null) {
            staggerOffset =
                    windowStagger.getStaggerOffset(context.getCurrentProcessingTime(), size);
        }
        long start =
                TimeWindow.getWindowStartWithOffset(
                        timestamp, (globalOffset + staggerOffset) % size, size);
        // 返回構(gòu)建好起止時(shí)間的TimeWindow
        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(...)'?");
    }
}

設(shè)置窗口觸發(fā)器Trigger

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

WindowAssigner與其主要實(shí)現(xiàn)類(lèi)的關(guān)系如下:

這些類(lèi)的含義分別如下

  • GlobalWindows:將所有元素分配進(jìn)同一個(gè)窗口的全局窗口分配器。
  • SlidingEventTimeWindows:基于事件時(shí)間的滑動(dòng)窗口分配器。
  • SlidingProcessingTimeWindows:基于處理時(shí)間的滑動(dòng)窗口分配器。
  • TumblingEventTimeWindows:基于事件時(shí)間的滾動(dòng)窗口分配器。
  • TumblingProcessingTimeWindows:基于處理時(shí)間的滾動(dòng)窗口分配器。
  • EventTimeSessionWindows:基于事件時(shí)間的會(huì)話窗口分配器。
  • ProcessingTimeSessionWindows:基于處理時(shí)間的會(huì)話窗口分配器。

Trigger

Trigger表示窗口觸發(fā)器。它是一個(gè)抽象類(lèi),主要定義了下面3個(gè)方法用于確定窗口何時(shí)觸發(fā)計(jì)算:

// 每個(gè)元素到來(lái)時(shí)觸發(fā)
public abstract TriggerResult onElement(T element, long timestamp, W window, TriggerContext ctx) throws Exception;
// 處理時(shí)間的定時(shí)器觸發(fā)時(shí)
public abstract TriggerResult onProcessingTime(long time, W window, TriggerContext ctx) throws Exception;
// 事件時(shí)間的定時(shí)器觸發(fā)時(shí)調(diào)用
public abstract TriggerResult onEventTime(long time, W window, TriggerContext ctx) throws Exception;

這3個(gè)方法的返回結(jié)果為T(mén)riggerResult對(duì)象。TriggerResult是一個(gè)枚舉類(lèi),包含兩個(gè)boolean類(lèi)型的字段fire和purge,分別表示窗口是否觸發(fā)計(jì)算和窗口內(nèi)的元素是否需要清空。

CONTINUE(false, false),
FIRE_AND_PURGE(true, true),
FIRE(true, false),
PURGE(false, true);

TriggerResult(boolean fire, boolean purge) {
    this.purge = purge;
    this.fire = fire;
}

窗口觸發(fā)器的實(shí)現(xiàn)由用戶根據(jù)業(yè)務(wù)需求自定義。Flink默認(rèn)基于事件時(shí)間的觸發(fā)器為EventTimeTrigger,其三個(gè)方法處理如下

@Override
public TriggerResult onElement(
        Object element, long timestamp, TimeWindow window, TriggerContext ctx)
        throws Exception {
    if (window.maxTimestamp() <= ctx.getCurrentWatermark()) {
        // 如果水印已經(jīng)超過(guò)窗口,則立即觸發(fā)
        return TriggerResult.FIRE;
    } else {
        // 注冊(cè)事件時(shí)間定時(shí)器
        ctx.registerEventTimeTimer(window.maxTimestamp());
        return TriggerResult.CONTINUE;
    }
}

@Override
public TriggerResult onEventTime(long time, TimeWindow window, TriggerContext ctx) {
    return time == window.maxTimestamp() ? TriggerResult.FIRE : TriggerResult.CONTINUE;
}

/*
 * 處理時(shí)間,窗口不觸發(fā)計(jì)算也不清空內(nèi)部元素。
 */
@Override
public TriggerResult onProcessingTime(long time, TimeWindow window, TriggerContext ctx)
        throws Exception {
    return TriggerResult.CONTINUE;
}

Trigger與其主要實(shí)現(xiàn)類(lèi)的繼承關(guān)系

這些類(lèi)的含義如下

  • CountTrigger:元素?cái)?shù)達(dá)到設(shè)置的個(gè)數(shù)時(shí)觸發(fā)計(jì)算的觸發(fā)器。
  • DeltaTrigger:基于DeltaFunction和設(shè)置的閾值觸發(fā)計(jì)算的觸發(fā)器。
  • EventTimeTrigger:基于事件時(shí)間的觸發(fā)器。
  • ProcessingTimeTrigger:基于處理時(shí)間的觸發(fā)器。
  • PurgingTrigger:可包裝其他觸發(fā)器的清空觸發(fā)器。
  • ContinuousEventTimeTrigger:基于事件時(shí)間并按照一定的時(shí)間間隔連續(xù)觸發(fā)計(jì)算的觸發(fā)器。
  • ContinuousProcessingTimeTrigger:基于處理時(shí)間并按照一定的時(shí)間間隔連續(xù)觸發(fā)計(jì)算的觸發(fā)器。

windowOperator

WindowedStream的構(gòu)造函數(shù)中,會(huì)生成WindowOperatorBuilder,該類(lèi)可以返回WindowOperator,這兩個(gè)類(lèi)負(fù)責(zé)窗口分配器、窗口觸發(fā)器和窗口剔除器這些組件在運(yùn)行時(shí)的協(xié)同工作。

對(duì)于WindowOperator,除了窗口分配器和窗口觸發(fā)器的相關(guān)字段,可以先了解下面兩個(gè)字段。

// StateDescriptor類(lèi)型,表示窗口狀態(tài)描述符。
private final StateDescriptor<? extends AppendingState<IN, ACC>, ?> windowStateDescriptor;

// 表示窗口的狀態(tài),窗口內(nèi)的元素都在其中維護(hù)。
private transient InternalAppendingState<K, W, IN, ACC, ACC> windowState;

窗口中的元素并沒(méi)有保存在Window對(duì)象中,而是維護(hù)在windowState中。windowStateDescriptor則是創(chuàng)建windowState所需用到的描述符。

當(dāng)有元素到來(lái)時(shí),會(huì)調(diào)用WindowOperator的processElement()方法:

public void processElement(StreamRecord<IN> element) throws Exception {
    // 分配窗口
    final Collection<W> elementWindows = windowAssigner.assignWindows(
        element.getValue(), element.getTimestamp(), windowAssignerContext);
            ...
        if (windowAssigner instanceof MergingWindowAssigner) { // Session Window的情況
            ...
        } else {
            for (W window: elementWindows) { // 非Session Window的情況
                ...
                // 將Window對(duì)象設(shè)置為namespace并添加元素到windowState中
                windowState.setCurrentNamespace(window);
                windowState.add(element.getValue());
                triggerContext.key = key;
                triggerContext.window = window;
                // 獲取TriggerResult,確定接下來(lái)是否需要觸發(fā)計(jì)算或清空窗口
                TriggerResult triggerResult = triggerContext.onElement(element);
                if (triggerResult.isFire()) {
                    ACC contents = windowState.get();
                    if (contents == null) {
                        continue;
                    }
                    // 觸發(fā)計(jì)算
                    emitWindowContents(window, contents);
                }
                if (triggerResult.isPurge()) {
                    // 清空窗口
                    windowState.clear();
                }
                ...
            }
        }
    ...
}

在處理時(shí)間或事件時(shí)間的定時(shí)器觸發(fā)時(shí),會(huì)調(diào)用WindowOperator的onProcessingTime()方法或onEventTime()方法,其中的邏輯與onElement()方法的大同小異。

Watermarks

水位線(watermark)是選用事件時(shí)間來(lái)進(jìn)行數(shù)據(jù)處理時(shí)特有的概念。它的本質(zhì)就是時(shí)間戳,從上游流向下游,表示系統(tǒng)認(rèn)為數(shù)據(jù)中的事件時(shí)間在該時(shí)間戳之前的數(shù)據(jù)都已到達(dá)。

Flink中,Watermark類(lèi)表示水位。

/** Creates a new watermark with the given timestamp in milliseconds. */
public Watermark(long timestamp) {
    this.timestamp = timestamp;
}

watermark的生成有兩種方式,這里不贅述,主要講述下基于配置的策略生成watermark的方式。如下的代碼是比較常見(jiàn)的配置:

// 分配事件時(shí)間與水印
.assignTimestampsAndWatermarks(
        // forBoundedOutOfOrderness 會(huì)根據(jù)事件的時(shí)間戳和允許的最大亂序時(shí)間生成水印。
        // Duration 設(shè)置了最大亂序時(shí)間為1秒。這意味著 Flink 將允許在這1秒的時(shí)間范圍內(nèi)的事件不按照事件時(shí)間的順序到達(dá),這個(gè)時(shí)間段內(nèi)的事件會(huì)被認(rèn)為是"有序的"。
        WatermarkStrategy.<Event>forBoundedOutOfOrderness(Duration.ofSeconds(1))
        // 設(shè)置事件時(shí)間分配器,從Event對(duì)象中提取時(shí)間戳作為事件時(shí)間
        .withTimestampAssigner(new SerializableTimestampAssigner<Event>() {
            @Override
            public long extractTimestamp(Event element, long recordTimestamp) {
                return element.timestamp;
            }
        }));

在Flink內(nèi)部,會(huì)根據(jù)配置的策略調(diào)用BoundedOutOfOrdernessWatermarks生成watermark。該類(lèi)的代碼如下:

public class BoundedOutOfOrdernessWatermarks<T> implements WatermarkGenerator<T> {

    /** The maximum timestamp encountered so far. */
    private long maxTimestamp;

    /** The maximum out-of-orderness that this watermark generator assumes. */
    private final long outOfOrdernessMillis;

    /**
     * Creates a new watermark generator with the given out-of-orderness bound.
     *
     * @param maxOutOfOrderness The bound for the out-of-orderness of the event timestamps.
     */
    public BoundedOutOfOrdernessWatermarks(Duration maxOutOfOrderness) {
        checkNotNull(maxOutOfOrderness, "maxOutOfOrderness");
        checkArgument(!maxOutOfOrderness.isNegative(), "maxOutOfOrderness cannot be negative");

        this.outOfOrdernessMillis = maxOutOfOrderness.toMillis();

        // start so that our lowest watermark would be Long.MIN_VALUE.
        this.maxTimestamp = Long.MIN_VALUE + outOfOrdernessMillis + 1;
    }

    // ------------------------------------------------------------------------

    @Override
    public void onEvent(T event, long eventTimestamp, WatermarkOutput output) {
        // 每條數(shù)據(jù)都會(huì)更新最大值
        maxTimestamp = Math.max(maxTimestamp, eventTimestamp);
    }

    @Override
    public void onPeriodicEmit(WatermarkOutput output) {
        // 發(fā)送 watermark 邏輯
        output.emitWatermark(new Watermark(maxTimestamp - outOfOrdernessMillis - 1));
    }
}

onEvent決定每次事件都會(huì)取得最大的事件時(shí)間更新;onPeriodicEmit則是周期性的更新并傳遞到下游。

AbstractStreamOperator

WatermarkGenerator接口的調(diào)用是在AbstractStreamOperator抽象類(lèi)的子類(lèi)TimestampsAndWatermarksOperator中。其生命周期open函數(shù)與每個(gè)數(shù)據(jù)到來(lái)的處理函數(shù)processElement,如下:

@Override
public void open() throws Exception {
    super.open();

    timestampAssigner = watermarkStrategy.createTimestampAssigner(this::getMetricGroup);
    watermarkGenerator =
            emitProgressiveWatermarks
                    ? watermarkStrategy.createWatermarkGenerator(this::getMetricGroup)
                    : new NoWatermarksGenerator<>();

    wmOutput = new WatermarkEmitter(output);

    watermarkInterval = getExecutionConfig().getAutoWatermarkInterval();
    if (watermarkInterval > 0 && emitProgressiveWatermarks) {
        final long now = getProcessingTimeService().getCurrentProcessingTime();
        getProcessingTimeService().registerTimer(now + watermarkInterval, this);
    }
}

@Override
public void processElement(final StreamRecord<T> element) throws Exception {
    final T event = element.getValue();
    final long previousTimestamp =
            element.hasTimestamp() ? element.getTimestamp() : Long.MIN_VALUE;
    // 從分配器中提取事件時(shí)間戳
    final long newTimestamp = timestampAssigner.extractTimestamp(event, previousTimestamp);

    element.setTimestamp(newTimestamp);
    output.collect(element);
    // 調(diào)用水印生成器
    watermarkGenerator.onEvent(event, newTimestamp, wmOutput);
}

從方法的入?yún)⒖梢钥闯鰜?lái) flink 算子間的數(shù)據(jù)流動(dòng)是 StreamRecord 對(duì)象。它對(duì)數(shù)據(jù)的處理邏輯是什么都不做直接向下游發(fā)送,然后調(diào)用 onEvent 記錄最大時(shí)間戳,也就是說(shuō):flink 是先發(fā)送數(shù)據(jù)再生成 watermark,watermark 永遠(yuǎn)在生成它的數(shù)據(jù)之后。

總結(jié)

上面的一系列相關(guān)代碼,只是冰山一角,暫時(shí)只是把關(guān)鍵涉及到的部分捋了一下。最后畫(huà)個(gè)圖,展示其大致思路。

參考:

Flink Watermark 源碼解析文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-746477.html

到了這里,關(guān)于聊聊Flink必知必會(huì)(五)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 必知必會(huì)Java

    必知必會(huì)Java

    你好,我是阿光。 最近想著把工作中使用過(guò)的java命令都梳理一下,方便日后查閱。雖然這類(lèi)文章很多,但自己梳理總結(jié)后,還是會(huì)有一些新的收獲。這也是這篇筆記的由來(lái)。 今天先聊聊 jps 命令。 jps 命令是JDK提供的一個(gè)工具,用于查看目標(biāo)系統(tǒng)上的Java進(jìn)程基本信息(進(jìn)程

    2024年02月05日
    瀏覽(21)
  • MySQL必知必會(huì)(初級(jí)篇)

    MySQL必知必會(huì)(初級(jí)篇)

    數(shù)據(jù)庫(kù) (DataBase,DB),是統(tǒng)一管理的、長(zhǎng)期存儲(chǔ)在計(jì)算機(jī)內(nèi)的、有組織的相關(guān)數(shù)據(jù)的集合。特點(diǎn)是數(shù)據(jù)見(jiàn)聯(lián)系密切、冗余度小、獨(dú)立性高、易擴(kuò)展,并且可以為各類(lèi)用戶共享。 MySQL :是一個(gè)關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng),由瑞典MySQL AB 公司開(kāi)發(fā),屬于 Oracle 旗下產(chǎn)品。MySQL 是最流行的

    2023年04月08日
    瀏覽(19)
  • 《SQL 必知必會(huì)》全解析

    不要哀求,學(xué)會(huì)爭(zhēng)取。若是如此,終有所獲。 原文:https://mp.weixin.qq.com/s/zbOqyAtsWsocarsFIGdGgw 你是否還在煩惱 SQL 該從何學(xué)起,或者學(xué)了 SQL 想找個(gè)地方練練手?好巧不巧,最近在工作之余登上???,發(fā)現(xiàn)了??筒恢郎稌r(shí)候上線了SQL 必知必會(huì)的練習(xí)題。 《SQL 必知必會(huì)》作為麻

    2024年02月08日
    瀏覽(27)
  • ChatGPT入門(mén)必知必會(huì)

    ChatGPT入門(mén)必知必會(huì)

    更多文章歡迎關(guān)注公眾號(hào): stackoveriow 2023年是真正意義上的AI之年,因?yàn)镃hatGPT 2007年,iPhone開(kāi)啟了智能手機(jī)時(shí)代, 2023年,我們迎來(lái)了人工智能時(shí)代,我們正處于歷史的大轉(zhuǎn)折點(diǎn)上,這也許是啟蒙運(yùn)動(dòng)級(jí)別的思想和社會(huì)轉(zhuǎn)折,工業(yè)革命級(jí)別的生產(chǎn)和生活轉(zhuǎn)折 。繼22年12月份從GP

    2023年04月18日
    瀏覽(31)
  • 【數(shù)據(jù)庫(kù)】索引必知必會(huì)

    【數(shù)據(jù)庫(kù)】索引必知必會(huì)

    數(shù)據(jù)庫(kù)中索引(Index)是一種幫助快速查找數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu),可以把它理解為書(shū)的目錄,通過(guò)索引能夠快速找到數(shù)據(jù)所在位置。 使用索引可以加快數(shù)據(jù)查找的效率,這是創(chuàng)建索引的最主要原因。 場(chǎng)景的索引數(shù)據(jù)結(jié)構(gòu)有:Hash表(通過(guò)hash算法快速定位數(shù)據(jù),但不適合范圍查詢,

    2023年04月20日
    瀏覽(26)
  • 抽象語(yǔ)法樹(shù)AST必知必會(huì)

    抽象語(yǔ)法樹(shù)AST必知必會(huì)

    打開(kāi)前端項(xiàng)目中的 package.json,會(huì)發(fā)現(xiàn)眾多工具已經(jīng)占據(jù)了我們開(kāi)發(fā)日常的各個(gè)角落,例如 JavaScript 轉(zhuǎn)譯、CSS 預(yù)處理、代碼壓縮、ESLint、Prettier 等。這些工具模塊大都不會(huì)交付到生產(chǎn)環(huán)境中,但它們的存在于我們的開(kāi)發(fā)而言是不可或缺的。 有沒(méi)有想過(guò)這些工具的功能是如何實(shí)

    2024年02月16日
    瀏覽(26)
  • 必知必會(huì)Java命令-jps

    必知必會(huì)Java命令-jps

    你好,我是阿光。 最近想著把工作中使用過(guò)的java命令都梳理一下,方便日后查閱。雖然這類(lèi)文章很多,但自己梳理總結(jié)后,還是會(huì)有一些新的收獲。這也是這篇筆記的由來(lái)。 今天先聊聊 jps 命令。 jps 命令是JDK提供的一個(gè)工具,用于查看目標(biāo)系統(tǒng)上的Java進(jìn)程基本信息(進(jìn)程

    2024年02月05日
    瀏覽(20)
  • 《MySQL 必知必會(huì)》課程筆記(三)

    《MySQL 必知必會(huì)》課程筆記(三)

    創(chuàng)建和修改數(shù)據(jù)表,是數(shù)據(jù)存儲(chǔ)過(guò)程中的重要?環(huán)。 我們不僅需要把表創(chuàng)建出來(lái),還需要正確地設(shè)置限定條件,這樣才能確保數(shù)據(jù)的一致性和完整性。 同時(shí),表中的數(shù)據(jù)會(huì)隨著業(yè)務(wù)需求的變化而變化,添加和修改相應(yīng)的字段也是常見(jiàn)的操作。 首先,我們要知道 MySQL 創(chuàng)建表的

    2024年02月03日
    瀏覽(22)
  • 緩存中間件Redis必知必會(huì)

    作者: 逍遙Sean 簡(jiǎn)介:一個(gè)主修Java的Web網(wǎng)站游戲服務(wù)器后端開(kāi)發(fā)者 主頁(yè):https://blog.csdn.net/Ureliable 覺(jué)得博主文章不錯(cuò)的話,可以三連支持一下~ 如有需要我的支持,請(qǐng)私信或評(píng)論留言! 前言: 本文是對(duì)redis的基本用法操作的整理。 如果需要在linux環(huán)境中搭建一個(gè)redis服務(wù)參考

    2024年02月11日
    瀏覽(17)
  • Python必知必會(huì) os 模塊詳解

    Python必知必會(huì) os 模塊詳解

    ?? 作者簡(jiǎn)介 :大家好我是小魚(yú)干兒?是一個(gè)熱愛(ài)編程、熱愛(ài)算法的大三學(xué)生,藍(lán)橋杯國(guó)賽二等獎(jiǎng)獲得者 ?? 個(gè)人主頁(yè) :https://blog.csdn.net/qq_52007481 ? 個(gè)人社區(qū) :【小魚(yú)干愛(ài)編程】 ?? 算法專(zhuān)欄 :算法競(jìng)賽進(jìn)階指南 ?? 刷題網(wǎng)站 :市面上的刷題網(wǎng)站有很多如何選擇一個(gè)適

    2024年02月03日
    瀏覽(44)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包