二、FIFO缓存

FIFO缓存

1.FIFO缓存介绍

FIFO(First-In-First-Out)缓存 是一种简单的缓存淘汰策略,它基于先进先出的原则来管理数据。当缓存达到容量限制并需要淘汰元素时,最先进入缓存的元素会被移除,以便为新元素腾出空间。

FIFO缓存的基本原则是:

①数据存储顺序:数据按照进入缓存的顺序排列(通常用队列实现)。最早插入的数据位于队列的前端,最新插入的数据位于队列的尾端。

②淘汰策略:当缓存已满,插入新数据时,队列前端的元素(最早插入的元素)被移除。

2.FIFO缓存实现

接下来我将通过c语言中的glib库来实现一个FIFO缓存结构。

首先给出结构体定义:

c 复制代码
// FIFO 缓存结构体
struct fifoCache {
    GList* elem_queue;          // 缓存数据链表
    int max_size;               // 缓存容量
    int size;                   // 当前缓存大小
    void (*free_elem)(void*);   // 数据释放函数
    int (*match_elem)(void* elem, void* user_data); // 数据匹配函数
};

需要实现如下功能:

c 复制代码
// 创建一个新的 FIFO 缓存
struct fifoCache* new_fifo_cache(int size, void (*free_elem)(void*),
                                 int (*match_elem)(void*, void*));

// 释放缓存及其中的所有元素
void free_fifo_cache(struct fifoCache* cache);

// 插入新数据到缓存
void fifo_cache_insert(struct fifoCache* cache, void* data);

// 查找元素(不改变数据顺序)
void* fifo_cache_lookup(struct fifoCache* cache, void* user_data);

// 条件删除满足用户自定义条件的元素
void fifo_cache_kicks(struct fifoCache* cache, void* user_data,
                      int (*func)(void* elem, void* user_data));

// 检查缓存是否已满
int fifo_cache_is_full(struct fifoCache* cache);

具体实现代码:

c 复制代码
#include <stdlib.h>
#include <stdio.h>
#include "fifo_cache.h"

// 创建一个新的 FIFO 缓存
struct fifoCache* new_fifo_cache(int size, void (*free_elem)(void*),
                                 int (*match_elem)(void*, void*)) {
    struct fifoCache* cache = malloc(sizeof(struct fifoCache));
    cache->elem_queue = NULL;
    cache->max_size = size;
    cache->size = 0;
    cache->free_elem = free_elem;
    cache->match_elem = match_elem;
    return cache;
}

// 释放缓存及其中的所有元素
void free_fifo_cache(struct fifoCache* cache) {
    if (cache == NULL) return;
    if (cache->free_elem) {
        g_list_free_full(cache->elem_queue, cache->free_elem);
    } else {
        g_list_free(cache->elem_queue);
    }
    free(cache);
}

// 插入新数据到缓存
void fifo_cache_insert(struct fifoCache* cache, void* data) {
    if (cache->size == cache->max_size) {
        // 淘汰队列头部数据
        GList* head = g_list_first(cache->elem_queue);
        if (cache->free_elem) {
            cache->free_elem(head->data);
        }
        cache->elem_queue = g_list_delete_link(cache->elem_queue, head);
        cache->size--;
    }
    // 插入新数据到队列尾部
    cache->elem_queue = g_list_append(cache->elem_queue, data);
    cache->size++;
}

// 查找元素(不改变数据顺序)
void* fifo_cache_lookup(struct fifoCache* cache, void* user_data) {
    GList* elem = g_list_first(cache->elem_queue);
    while (elem) {
        if (cache->match_elem(elem->data, user_data)) {
            return elem->data;
        }
        elem = g_list_next(elem);
    }
    return NULL; // 未找到
}

// 条件删除满足用户自定义条件的元素
void fifo_cache_kicks(struct fifoCache* cache, void* user_data,
                      int (*func)(void* elem, void* user_data)) {
    GList* elem = g_list_first(cache->elem_queue);
    while (elem) {
        if (func(elem->data, user_data)) {
            if (cache->free_elem) {
                cache->free_elem(elem->data);
            }
            cache->elem_queue = g_list_delete_link(cache->elem_queue, elem);
            cache->size--;
            break;
        }
        elem = g_list_next(elem);
    }
}

// 检查缓存是否已满
int fifo_cache_is_full(struct fifoCache* cache) {
    return cache->size >= cache->max_size;
}

测试代码:

c 复制代码
#include "fifo_cache.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 自定义数据类型
typedef struct {
    char* name;
} Data;

// 数据释放函数
void free_data(void* data) {
    Data* d = (Data*)data;
    printf("[Free] Name = %s\n", d->name);
    free(d->name);
    free(d);
}

// 数据匹配函数
int match_data(void* elem, void* user_data) {
    Data* d = (Data*)elem;
    char* target = (char*)user_data;
    return strcmp(d->name, target) == 0;
}

int main() {
    printf("---- FIFO Cache Test ----\n");

    struct fifoCache* cache = new_fifo_cache(3, free_data, match_data);

    // 插入数据
    printf("[Insert] Alice, Bob, Charlie\n");
    Data* a = malloc(sizeof(Data)); a->name = strdup("Alice");
    Data* b = malloc(sizeof(Data)); b->name = strdup("Bob");
    Data* c = malloc(sizeof(Data)); c->name = strdup("Charlie");
    fifo_cache_insert(cache, a);
    fifo_cache_insert(cache, b);
    fifo_cache_insert(cache, c);

    // 查找数据
    printf("Looking up: Bob\n");
    Data* result = (Data*)fifo_cache_lookup(cache, "Bob");
    if (result) printf("Found: %s\n", result->name);

    // 插入新数据,触发淘汰
    printf("[Insert] "Dave"\n");
    Data* d = malloc(sizeof(Data)); d->name = strdup("Dave");
    fifo_cache_insert(cache, d);

    // 查找被淘汰的数据
    printf("Looking up: Alice\n");
    result = (Data*)fifo_cache_lookup(cache, "Alice");
    if (!result) printf("Alice has been evicted.\n");

    free_fifo_cache(cache);
    printf("---- Test Complete ----\n");
    return 0;
}

测试结果:

同样的,上面的FIFO缓存支持任意的数据类型,具有高度的通用性和灵活性。

3.FIFO缓存总结

FIFO缓存应用:

应用场景 说明
任务调度 在操作系统中,FIFO 用于管理任务队列,确保任务按照到达的顺序执行。
页面置换 在内存管理中,FIFO 用于页面置换,淘汰最早加载的页面,释放内存空间。
网络数据包缓存 在网络交换机和路由器中,FIFO 用于管理数据包队列,按照顺序传输或丢弃数据包。
日志管理 适合简单的日志记录,按照记录顺序缓存和清理日志数据。
数据缓冲区 在流式数据处理中,FIFO 用于临时存储数据,确保数据按顺序读取和处理。
消息队列 实现生产者-消费者模型中的消息传递,保证消息按插入顺序进行处理。

FIFO缓存优缺点:

优点 说明
实现简单 基于队列数据结构,逻辑清晰,易于实现。
插入和删除效率高 在队列的尾部插入、头部删除,时间复杂度为 O(1)。
公平性 数据按照到达顺序被处理,没有优先级差异。
适合访问模式简单、数据均匀的场景 适合不需要热点数据的简单缓存需求。
缺点 说明
无法处理热点数据 即使频繁访问的数据也不会改变淘汰顺序,可能被淘汰。
缓存利用率低 在访问模式复杂的场景下,缓存命中率较低。
不考虑数据的访问频率或时间 与 LRU 或 LFU 相比,无法根据访问频率或时间进行智能淘汰。
适用于简单场景 不适合需要高度优化性能的复杂系统。

总结:FIFO 缓存是一种简单高效的缓存淘汰策略,适用于数据访问均匀且热点数据不明显的场景。它的实现依赖于队列结构,逻辑清晰,插入和删除操作性能高。然而,在访问热点数据频繁的应用中,FIFO 的性能可能不如 LRU 和 LFU 等策略。在实际应用中,FIFO 适合简单场景,比如任务调度、数据缓冲区 和 日志管理,但在复杂缓存场景下,可能需要结合其他策略实现更高的缓存命中率。

相关推荐
小码ssim41 分钟前
docker搭建Redis集群及哨兵(windows10环境,OSS Cluster)
数据库·redis·缓存
SUDO-12 小时前
Redis集合运算的应用场景
数据库·redis·缓存
古城小栈3 小时前
接口数据做缓存,响应飞快似天神
java·spring boot·缓存
Sunmanit6 小时前
异步将用户信息存入 Redis 缓存
java·数据库·redis·缓存
Steven_Mmm6 小时前
高并发-缓存预热
redis·缓存
better_zhang9 小时前
maven 中 有历史模块缓存 怎么清
java·缓存·maven
席万里1 天前
Redis事务和消息队列【Redis场景下篇】
数据库·redis·缓存
码农派大星。1 天前
redis数据类型(二)
数据库·redis·缓存
初晴~1 天前
【Redis】高并发场景下秒杀业务的实现思路(单机模式)
java·数据库·redis·后端·spring·缓存·中间件