Rumah >pangkalan data >Redis >Bagaimana untuk melaksanakan lapisan bawah senarai terpaut Redis

Bagaimana untuk melaksanakan lapisan bawah senarai terpaut Redis

WBOY
WBOYke hadapan
2023-05-28 22:46:581492semak imbas

Pelaksanaan asas

Bagaimana untuk melaksanakan lapisan bawah senarai terpaut Redis

Pelaksanaan asas struktur data senarai Redis adalah berdasarkan senarai terpaut dua kali. Senarai terpaut berganda ialah struktur data biasa yang terdiri daripada satu siri nod Setiap nod diwakili oleh struktur listNode, yang mengandungi penunjuk prev menunjuk ke nod sebelumnya, penunjuk seterusnya menunjuk ke nod seterusnya dan storan Penunjuk A. untuk nilai nilai. Senarai terpaut berganda dalam Redis terdiri daripada nod, setiap nod mewakili elemen dan disambungkan melalui penunjuk.

Kelebihan senarai terpaut berganda ialah operasi sisipan dan pemadaman boleh dilakukan dengan cepat di bahagian kepala dan ekor. Dalam Redis, apabila elemen baharu dimasukkan ke dalam kepala atau ekor Senarai, anda hanya perlu mengubah suai penunjuk sebelumnya dan seterusnya nod baharu dan penuding sebelumnya atau seterusnya bagi nod kepala atau ekor asal untuk melengkapkan operasi sisipan . Masa adalah rumit. Begitu juga, apabila elemen dipadamkan, anda hanya perlu mengubah suai penuding seterusnya bagi nod sebelumnya atau penuding sebelumnya bagi nod seterusnya untuk melengkapkan operasi pemadaman, dan kerumitan masa juga O(1).

Redis menggunakan teknik lain untuk meningkatkan prestasi struktur data Senarai, di samping menggunakan senarai terpaut dua kali. Sebagai contoh, apabila bilangan elemen dalam Senarai melebihi ambang tertentu, Redis akan menukar Senarai kepada senarai termampat (senarai zip), yang boleh mengurangkan penggunaan memori dan meningkatkan kelajuan akses. Apabila lelaran ke atas Senarai, Redis menggunakan lelaran untuk melintasi elemen dalam Senarai, yang boleh mengelakkan ralat yang disebabkan oleh mengubah suai Senarai semasa proses traversal.

Bagaimana untuk melaksanakan lapisan bawah senarai terpaut Redis

Struktur data jenis senarai Redis membenarkan menambah atau mengalih keluar elemen pada permulaan atau akhir senarai dan memasukkan atau memadam elemen pada kedudukan yang ditentukan. Operasi ini boleh diselesaikan dalam masa yang tetap kerana pelaksanaan senarai terpaut dua kali Redis menyokong akses pantas ke nod kepala dan ekor, serta memasukkan dan memadam nod di lokasi yang ditentukan.

Bagaimana untuk melaksanakan lapisan bawah senarai terpaut Redis

Berikut ialah beberapa operasi senarai Redis biasa dan kerumitan masanya:

  • LPUSH: masukkan elemen di kepala, masa kerumitan ialah O(1).

  • RPUSH: Masukkan elemen pada penghujung, kerumitan masa ialah O(1).

  • LPOP: Padamkan elemen pengepala, kerumitan masa ialah O(1).

  • RPOP: padamkan elemen ekor, kerumitan masa ialah O(1).

  • LINDEX: Akses elemen pada kedudukan yang ditentukan, kerumitan masa ialah O(n).

  • LINSERT: Masukkan elemen pada kedudukan yang ditentukan, kerumitan masa ialah O(n).

  • LREM: Padamkan elemen yang ditentukan, kerumitan masa ialah O(n).

Bagaimana untuk melaksanakan lapisan bawah senarai terpaut Redis

Pelaksanaan kod sumber

Demo pelaksanaan kod asas struktur data Senarai Redis dilaksanakan dalam bahasa C:

typedef struct listNode {
    struct listNode *prev;
    struct listNode *next;
    void *value;
} listNode;

typedef struct list {
    listNode *head;
    listNode *tail;
    unsigned long len;
} list;

list *listCreate(void) {
    list *l;

    if ((l = malloc(sizeof(*l))) == NULL) return NULL;
    l->head = l->tail = NULL;
    l->len = 0;
    return l;
}

void listRelease(list *list) {
    unsigned long len;
    listNode *current, *next;

    current = list->head;
    len = list->len;
    while(len--) {
        next = current->next;
        free(current);
        current = next;
    }
    free(list);
}

listNode *listAddNodeHead(list *list, void *value) {
    listNode *node;

    if ((node = malloc(sizeof(*node))) == NULL) return NULL;
    node->value = value;
    if (list->len == 0) {
        list->head = list->tail = node;
        node->prev = node->next = NULL;
    } else {
        node->prev = NULL;
        node->next = list->head;
        list->head->prev = node;
        list->head = node;
    }
    list->len++;
    return node;
}

listNode *listAddNodeTail(list *list, void *value) {
    listNode *node;

    if ((node = malloc(sizeof(*node))) == NULL) return NULL;
    node->value = value;
    if (list->len == 0) {
        list->head = list->tail = node;
        node->prev = node->next = NULL;
    } else {
        node->prev = list->tail;
        node->next = NULL;
        list->tail->next = node;
        list->tail = node;
    }
    list->len++;
    return node;
}

void listDelNode(list *list, listNode *node) {
    if (node->prev)
        node->prev->next = node->next;
    else
        list->head = node->next;
    if (node->next)
        node->next->prev = node->prev;
    else
        list->tail = node->prev;
    free(node);
    list->len--;
}

Kod di atas melaksanakan operasi asas struktur data Senarai, termasuk mencipta Senarai, mengeluarkan Senarai, memasukkan elemen di kepala dan ekor serta memadamkan elemen. Kerumitan masa bagi operasi ini ialah O(1).

Kegunaan praktikal dalam pengeluaran

Struktur data Senarai Redis mempunyai banyak kegunaan hebat dalam persekitaran pengeluaran:

  • Baris gilir mesej: Senarai Redis boleh digunakan sebagai baris gilir mesej, Pengeluar menolak mesej ke dalam Senarai, dan pengguna memperoleh mesej dan memprosesnya secara menyekat melalui arahan seperti blpop dan brpop, dengan itu merealisasikan baris gilir mesej yang mudah.

  • Senarai kedudukan: Operasi tolak dan pop Senarai Redis kedua-duanya mempunyai kerumitan masa O(1) Markah pengguna boleh disimpan dalam Senarai sebagai nilai dan kemudian diperoleh melalui Perintah lrange.

  • Senarai Kenalan Terkini: ID kenalan terbaru pengguna boleh disimpan dalam Senarai, dan apabila pengguna berinteraksi dengan kenalan, ID kenalan itu dialihkan ke Ketua Senarai, supaya senarai kenalan terbaru pengguna boleh diperolehi melalui perintah lrange.

  • Pertanyaan paging: Anda boleh menyimpan data dalam Senarai dan kemudian gunakan perintah lrange untuk melaksanakan pertanyaan paging.

  • Log perlahan: Redis boleh merekod arahan yang masa pelaksanaannya melebihi ambang tertentu, menyimpan maklumat arahan ini dalam Senarai dan mendapatkan maklumat log perlahan melalui perintah lrange.

  • Bilik sembang: Anda boleh menyimpan mesej dalam bilik sembang dalam Senarai Apabila terdapat mesej baharu, tolaknya ke Senarai, dan kemudian dapatkan mesej terbaharu melalui julat perintah.

  • Baris gilir tugas: Anda boleh menyimpan tugasan yang perlu dilaksanakan dalam Senarai, dan kemudian mendapatkan tugasan melalui arahan lpop dan melaksanakannya.

  • Statistik data masa nyata: Anda boleh menyimpan data masa nyata dalam Senarai, dan kemudian menggunakan perintah lrange untuk mendapatkan data dalam julat masa tertentu dan melakukan analisis statistik.

  • 队列延迟处理:可以将需要延迟处理的任务存储在 List 中,同时将任务的执行时间作为 score 存储在 Sorted Set 中,然后使用 Redis 的定时任务功能,每隔一段时间就将 Sorted Set 中过期的任务移动到 List 中,然后通过 lpop 命令获取任务并执行。

  • 日志收集:可以将应用程序的日志信息存储在 List 中,然后通过 lrange 命令获取日志信息进行分析和处理。

实战实例

基于 Redis List 数据结构实现消息队列的 Java 代码示例:

import redis.clients.jedis.Jedis;

public class RedisMessageQueue {
    private Jedis jedis;
    private String queueKey;

    public RedisMessageQueue(Jedis jedis, String queueKey) {
        this.jedis = jedis;
        this.queueKey = queueKey;
    }

    public void enqueue(String message) {
        jedis.rpush(queueKey, message);
    }

    public String dequeue() {
        return jedis.lpop(queueKey);
    }
}

示例中,定义了一个 RedisMessageQueue 类,包含一个 Jedis 对象和一个队列键名 queueKey。enqueue 方法用于将消息 push 到队列中,dequeue 方法用于从队列中获取消息并将其 pop 出来,使用该类可以方便地实现消息队列功能。

使用方法如下:

import redis.clients.jedis.Jedis;

public class TestRedisMessageQueue {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("localhost");
        RedisMessageQueue queue = new RedisMessageQueue(jedis, "myqueue");

        // 生产者向队列中添加消息
        queue.enqueue("Hello, Redis!");
        queue.enqueue("How are you?");

        // 消费者从队列中获取消息
        String message = queue.dequeue();
        while (message != null) {
            System.out.println("Received message: " + message);
            message = queue.dequeue();
        }
    }
}

我已经构建了一个 RedisMessageQueue 实例,并向队列中添加了两条信息。接着,调用 dequeue 方法从队列中取出消息,并将其输出到控制台。

该示例代码仅为演示 Redis List 数据结构实现消息队列的思路,实际生产环境中需要考虑更多的细节问题,例如如何处理消息重复、如何保证消息的可靠性等等。

Redis 聊天室示例

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;

import java.util.Scanner;

public class RedisChatRoom {
    private Jedis jedis;
    private String channel;
    private String chatListKey;

    public RedisChatRoom(Jedis jedis, String channel, String chatListKey) {
        this.jedis = jedis;
        this.channel = channel;
        this.chatListKey = chatListKey;
    }

    public void start() {
        // 订阅 Redis 频道
        jedis.subscribe(new JedisPubSub() {
            @Override
            public void onMessage(String channel, String message) {
                System.out.println("Received message: " + message);
                // 将消息添加到聊天列表中
                jedis.rpush(chatListKey, message);
            }
        }, channel);

        // 发布消息到 Redis 频道
        Scanner scanner = new Scanner(System.in);
        while (true) {
            System.out.print("Enter message: ");
            String message = scanner.nextLine();
            jedis.publish(channel, message);
        }
    }

    public void printChatList() {
        // 获取聊天列表中的所有消息并输出到控制台
        System.out.println("Chat list:");
        for (String message : jedis.lrange(chatListKey, 0, -1)) {
            System.out.println(message);
        }
    }
}

示例中,RedisChatRoom 类中添加了一个聊天列表 chatListKey,用于存储聊天室中的所有消息。在订阅 Redis 频道时,通过 JedisPubSub 的 onMessage 方法将收到的消息添加到聊天列表中。在 printChatList 方法中,通过 lrange 命令获取聊天列表中的所有消息,并输出到控制台中。

使用方法如下:

import redis.clients.jedis.Jedis;

public class TestRedisChatRoom {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("localhost");
        RedisChatRoom chatRoom = new RedisChatRoom(jedis, "mychannel", "mychatlist");
        chatRoom.start();
        chatRoom.printChatList();
    }
}

创建了一个 RedisChatRoom 对象,并指定了频道名为 mychannel 和聊天列表键名为 mychatlist。执行 start 方法即可开始 Redis 频道的订阅并发布消息。在最后一步中,使用 printChatList 方法从聊天列表中获取所有消息并输出到控制台上。

该示例仅仅简单演示 Redis List 数据结构实现聊天室的思路,实际项目中需要更周全的设计以及考虑。

Atas ialah kandungan terperinci Bagaimana untuk melaksanakan lapisan bawah senarai terpaut Redis. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:yisu.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam