C# 动态字典(可以随机实时增删访问,保证先入先出的字典)

在这里插入图片描述

如果你有以下需求:
1. 需要对Dictionary进行遍历的同时移除或者添加元素
2. 需要按顺序遍历Dictionary并且保证先入先出
3. 需要即时的获取字典内的元素数量,即时增删


如果你觉得好,请给我的框架点一个免费的star,球球啦
Yueh0607 - AirFramework


动态字典实现

/********************************************************************************************
 * Date : 2023.1.30
 * Description : 
 * 可顺序遍历且可以随机移除的队列
 * 
 * 遍历方法例程:
 * 
            _modules.ResetTraversalCount();
            int traversalCount = _modules.TraversalCount;    
            for (int i = 0; i < traversalCount; ++i)
            {
                if (_modules.TryDequeue(out IModule module, out Type key))
                {
                    module.OnUpdate();
                    _modules.TryEnqueue(key, module);
                }
            }
 * 
 * 
 ********************************************************************************************/


using System;
using System.Collections;
using System.Collections.Generic;
namespace AirFramework
{
    public class DynamicDictionary<T, K> : IEnumerable<KeyValuePair<T, K>> where T : notnull
    {

        //队列顺序
        private readonly Queue<T> queue;
        //实际存储键值对,即时
        private readonly Dictionary<T, K> dictionary;
        //临时移除状态
        private readonly Dictionary<T, int> state;

        /// <summary>
        /// 真正剩余元素数量
        /// </summary>
        public int Count => dictionary.Count;

        /// <summary>
        /// 遍历出队的次数
        /// </summary>
        public int TraversalCount { get; private set; } = 0;

        /// <summary>
        /// 刷新遍历数量,在每次遍历之前都要进行一次刷新以校准遍历数量
        /// </summary>
        public int ResetTraversalCount() => TraversalCount = queue.Count;

        public DynamicDictionary()
        {
            queue = new Queue<T>();
            dictionary = new Dictionary<T, K>();
            state = new Dictionary<T, int>();
        }

        /// <summary>
        /// 通过自定义比较器来提高字典比较效率的构造方式
        /// </summary>
        /// <param name="equalityComparer"></param>
        public DynamicDictionary(IEqualityComparer<T> equalityComparer)
        {
            queue = new Queue<T>();
            dictionary = new Dictionary<T, K>(equalityComparer);
            state = new Dictionary<T, int>(equalityComparer);
        }


        /// <summary>
        /// 入队
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public void Enqueue(T key, K value)
        {
            if (TryEnqueue(key, value)) return;
            throw new InvalidOperationException("The operation on an empty container is invalid");
        }
        /// <summary>
        /// 尝试入队
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool TryEnqueue(T key, K value)
        {
            if (!dictionary.TryAdd(key, value))
            {
                return false;
            }
            queue.Enqueue(key);
            return true;
        }
        /// <summary>
        /// 从队中移除
        /// </summary>
        /// <param name="key"></param>
        public void Remove(T key)
        {
            if (!TryRemove(key))
            {
                throw new InvalidOperationException("The operation on an empty container is invalid");
            }
        }
        /// <summary>
        /// 尝试从队中移除
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool TryRemove(T key)
        {
            if (dictionary.ContainsKey(key))
            {
                dictionary.Remove(key);
                if (state.ContainsKey(key)) state[key]++;
                else state.Add(key, 1);
                return true;
            }
            return false;
        }

        /// <summary>
        /// 尝试获取队首
        /// </summary>
        /// <param name="result"></param>
        /// <returns></returns>
        public bool TryPeek(out K result)
        {
            do
            {
                if (queue.TryPeek(out var key))
                {
                    if (state.TryGetValue(key, out int count))
                    {
                        state[key] = --count;
                        if (TraversalCount > 0) TraversalCount--;
                        if (count == 0) state.Remove(key);
                        queue.Dequeue();
                    }
                    else return dictionary.TryGetValue(key, out result);
                }
                else
                {
                    result = default;
                    return false;
                }
            }
            while (true);
        }
        /// <summary>
        /// 获取队首
        /// </summary>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        public K Peek()
        {
            if (TryPeek(out var result)) return result;
            throw new InvalidOperationException("The operation on an empty container is invalid");
        }
        /// <summary>
        /// 尝试出队
        /// </summary>
        /// <param name="result"></param>
        /// <returns></returns>
        public bool TryDequeue(out K result)
        {
            return TryDequeue(out result, out _);
        }
        /// <summary>
        /// 尝试出队
        /// </summary>
        /// <param name="result"></param>
        /// <param name="k"></param>
        /// <returns></returns>
        public bool TryDequeue(out K result, out T k)
        {
            if (queue.TryDequeue(out var key))
            {
                while (state.TryGetValue(key, out var count))
                {
                    state[key] = --count;
                    if (TraversalCount > 0) TraversalCount--;
                    if (count == 0) state.Remove(key);
                    if (!queue.TryDequeue(out key))
                    {
                        result = default;
                        k = default;
                        return false;
                    }
                }
                if (dictionary.TryGetValue(key, out result))
                {
                    k = key;
                    dictionary.Remove(key);
                    return true;
                }
            }

            result = default;
            k = default;
            return false;
        }

        /// <summary>
        /// 出队
        /// </summary>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        public K Dequeue()
        {
            if (TryDequeue(out var result))
            {
                return result;
            }
            throw new InvalidOperationException("The operation on an empty container is invalid");
        }

        /// <summary>
        /// 访问以K为键的对象
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public K this[T key]
        {
            get => dictionary[key];
            set => dictionary[key] = value;
        }
        /// <summary>
        /// 是否存在以K为键的对象
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool ContainsKey(T key) => dictionary.ContainsKey(key);

        /// <summary>
        /// 清空
        /// </summary>
        public void Clear()
        {
            dictionary.Clear();
            queue.Clear();
            state.Clear();
        }


        /// <summary>
        /// 无序遍历  不可动态随机移除  迭代器
        /// </summary>
        /// <returns></returns>
        public IEnumerator<KeyValuePair<T, K>> GetEnumerator()
        {
            return dictionary.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return dictionary.GetEnumerator();
        }
    }
}

配套拓展方法

using System;
namespace AirFramework
{
    public static class DynamicDictionaryExtensions
    {
        /// <summary>
        /// 从动态字典获取一个值,如果值不存在则返回传入的默认值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="K"></typeparam>
        /// <param name="dictionary"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static K GetValueOrDefault<T, K>(this DynamicDictionary<T, K> dictionary, T key, K value = default)
        {
            if (dictionary.ContainsKey(key))
            {
                return dictionary[key];
            }
            return value;

        }
        /// <summary>
        /// 从动态字典获取一个值,如果不存在则添加指定值后返回该值
        /// </summary>
        /// <typeparam name="T">键类型</typeparam>
        /// <typeparam name="K">值类型</typeparam>
        /// <param name="dictionary">动态字典</param>
        /// <param name="key">键</param>
        /// <param name="value">默认值</param>
        /// <returns>值</returns>
        public static K GetValueOrAddDefault<T, K>(this DynamicDictionary<T, K> dictionary, T key, K value = default)
        {
            if (dictionary.ContainsKey(key))
            {
                return dictionary[key];
            }
            dictionary.Enqueue(key, value);
            return dictionary[key];
        }
        /// <summary>
        /// 从动态字典获取一个值,如果不存在则添加指定值后返回该值
        /// </summary>
        /// <typeparam name="T">键类型</typeparam>
        /// <typeparam name="K">值类型</typeparam>
        /// <param name="dictionary">动态字典</param>
        /// <param name="key">键</param>
        /// <param name="value">默认值</param>
        /// <returns>值</returns>
        public static K GetValueOrAddDefault<T, K>(this DynamicDictionary<T, K> dictionary, T key, Func<K> getter = null)
        {
            if (dictionary.ContainsKey(key))
            {
                return dictionary[key];
            }

            dictionary.Enqueue(key, getter == null ? default : getter());
            return dictionary[key];
        }

        /// <summary>
        /// 尝试从动态字典获取一个值,如果该值存在则返回true并传出Value
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="K"></typeparam>
        /// <param name="dictionary"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool TryGetValue<T, K>(this DynamicDictionary<T, K> dictionary, T key, out K value)
        {
            if (dictionary.ContainsKey(key))
            {
                value = dictionary[key];
                return true;
            }
            value = default;
            return false;
        }

        /// <summary>
        /// 尝试从动态字典获取一个值,如果该值存在则返回true并传出Value
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="K"></typeparam>
        /// <param name="dictionary"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool GetValueOrDefault<T, K>(this DynamicDictionary<T, K> dictionary, T key, out K value)
        {
            if (dictionary.ContainsKey(key))
            {
                value = dictionary[key];
                return true;
            }
            value = default;
            return false;
        }


        /// <summary>
        /// 尝试从动态字典移除一个值并调用Dispose,如果该值存在则返回true
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="K"></typeparam>
        /// <param name="dictionary"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool TryRemoveAndDispose<T, K>(this DynamicDictionary<T, K> dictionary, T key) where K : IDisposable
        {
            if (dictionary.TryGetValue(key, out var value))
            {
                value.Dispose();
                return true;
            }
            return false;
        }

        /// <summary>
        /// 从动态字典移除一个值并调用其Dispose方法,如果该值不存在将引发异常
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="K"></typeparam>
        /// <param name="dictionary"></param>
        /// <param name="key"></param>
        public static void RemoveAndDispose<T, K>(this DynamicDictionary<T, K> dictionary, T key) where K : IDisposable
        {
            dictionary.Remove(key);
            dictionary[key].Dispose();
        }

        /// <summary>
        /// 清空动态字典并调用所有元素的Dispose方法s
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="K"></typeparam>
        /// <param name="dictionary"></param>
        public static void ClearAndDispose<T, K>(this DynamicDictionary<T, K> dictionary) where K : IDisposable
        {
            while (dictionary.Count > 0)
            {
                dictionary.Dequeue().Dispose();
            }
        }
    }
}

动态HashSet的实现

/********************************************************************************************
 * Date : 2023.1.30
 * Description : 
 * 可顺序遍历且可以随机移除的队列
 * 
 * 遍历方法例程:
 * 
            _modules.ResetTraversalCount();
            int traversalCount = _modules.TraversalCount;    
            for (int i = 0; i < traversalCount; ++i)
            {
                if (_modules.TryDequeue(out IModule module))
                {
                    module.OnUpdate();
                    _modules.TryEnqueue( module);
                }
            }
 * 
 * 
 ********************************************************************************************/


using System;
using System.Collections;
using System.Collections.Generic;
namespace AirFramework
{
    public class DynamicHashSet<T> : IEnumerable<T> where T : notnull
    {

        //队列顺序
        private readonly Queue<T> queue;
        //实际存储键值对,即时
        private readonly HashSet<T> hashSet;
        //临时移除状态
        private readonly Dictionary<T, int> state;

        /// <summary>
        /// 真正剩余元素数量
        /// </summary>
        public int Count => hashSet.Count;

        /// <summary>
        /// 遍历出队的次数
        /// </summary>
        public int TraversalCount { get; private set; } = 0;

        /// <summary>
        /// 刷新遍历数量,在每次遍历之前都要进行一次刷新以校准遍历数量
        /// </summary>
        public int ResetTraversalCount() => TraversalCount = queue.Count;

        public DynamicHashSet()
        {
            queue = new Queue<T>();
            hashSet = new HashSet<T>();
            state = new Dictionary<T, int>();
        }

        /// <summary>
        /// 通过自定义比较器来提高比较效率的构造方式
        /// </summary>
        /// <param name="equalityComparer"></param>
        public DynamicHashSet(IEqualityComparer<T> equalityComparer)
        {
            queue = new Queue<T>();
            hashSet = new HashSet<T>(equalityComparer);
            state = new Dictionary<T, int>(equalityComparer);
        }


        /// <summary>
        /// 入队
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public void Enqueue(T key)
        {
            if (TryEnqueue(key)) return;
            throw new ArgumentException("Same key exists");
        }
        /// <summary>
        /// 尝试入队
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool TryEnqueue(T key)
        {
            if (!hashSet.TryAdd(key)) return false;
            queue.Enqueue(key);
            return true;
        }
        /// <summary>
        /// 从队中移除
        /// </summary>
        /// <param name="key"></param>
        public void Remove(T key)
        {
            if (!TryRemove(key)) throw new ArgumentException("error remove key ");
        }
        /// <summary>
        /// 尝试从队中移除
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool TryRemove(T key)
        {
            if (hashSet.Contains(key))
            {
                hashSet.Remove(key);
                if (state.ContainsKey(key)) state[key]++;
                else state.Add(key, 1);
                return true;
            }
            return false;
        }

        /// <summary>
        /// 尝试获取队首
        /// </summary>
        /// <param name="result"></param>
        /// <returns></returns>
        public bool TryPeek(out T result)
        {
            do
            {
                if (queue.TryPeek(out var key))
                {
                    if (state.TryGetValue(key, out int count))
                    {
                        state[key] = --count;
                        if (TraversalCount > 0) TraversalCount--;
                        if (count == 0) state.Remove(key);
                        queue.Dequeue();
                    }
                    else return hashSet.TryGetValue(key, out result);
                }
                else
                {
                    result = default;
                    return false;
                }
            }
            while (true);
        }
        /// <summary>
        /// 获取队首
        /// </summary>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        public T Peek()
        {
            if (TryPeek(out var result)) return result;
            throw new InvalidOperationException("The operation on an empty container is invalid");
        }

        /// <summary>
        /// 尝试出队
        /// </summary>
        /// <param name="result"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        public bool TryDequeue(out T result)
        {
            if (queue.TryDequeue(out var key))
            {
                while (state.TryGetValue(key, out var count))
                {
                    state[key] = --count;
                    if (TraversalCount > 0) TraversalCount--;
                    if (count == 0) state.Remove(key);
                    if (!queue.TryDequeue(out key))
                    {
                        result = default;
                        return false;
                    }
                }
                if (hashSet.Contains(key))
                {
                    result = key;
                    hashSet.Remove(key);
                    return true;
                }
            }
            result = default;
            return false;
        }

        /// <summary>
        /// 出队
        /// </summary>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        public T Dequeue()
        {
            if (TryDequeue(out var result))
            {
                return result;
            }
            throw new InvalidOperationException("The operation on an empty container is invalid");
        }


        /// <summary>
        /// 是否存在Key对象
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool Contains(T key) => hashSet.Contains(key);

        /// <summary>
        /// 清空
        /// </summary>
        public void Clear()
        {
            hashSet.Clear();
            queue.Clear();
            state.Clear();
        }


        /// <summary>
        /// 无序遍历  不可动态随机移除  迭代器
        /// </summary>
        /// <returns></returns>
        public IEnumerator<T> GetEnumerator()
        {
            return hashSet.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return hashSet.GetEnumerator();
        }
    }
}



配套拓展方法

using System;
namespace AirFramework
{
    public static class DynamicHashSetExtensions
    {

        /// <summary>
        /// 尝试从动态HashSet移除一个值并调用Dispose,如果该值存在则返回true
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="K"></typeparam>
        /// <param name="hashSet"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool TryRemoveAndDispose<T>(this DynamicHashSet<T> hashSet, T key) where T : IDisposable
        {
            if (hashSet.Contains(key))
            {
                key.Dispose();
                return true;
            }
            return false;
        }

        /// <summary>
        /// 从动态字典移除一个值并调用其Dispose方法,如果该值不存在将引发异常
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="K"></typeparam>
        /// <param name="hashSet"></param>
        /// <param name="key"></param>
        public static void RemoveAndDispose<T, K>(this DynamicHashSet<T> hashSet, T key) where T : IDisposable
        {
            hashSet.Remove(key);
            key.Dispose();
        }

        /// <summary>
        /// 清空动态字典并调用所有元素的Dispose方法s
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="hashSet"></param>
        public static void ClearAndDispose<T>(this DynamicHashSet<T> hashSet) where T : IDisposable
        {
            while (hashSet.Count > 0)
            {
                hashSet.Dequeue().Dispose();
            }
        }
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

TX Barcode .NET for WPF Crack

TX Barcode .NET for WPF Crack 用于WPF软件的TX Barcode.NET包括一天完成的功能以及用于WPF的软件的2D条形码控制。 用于WPF的TX Barcode.NET的功能和属性&#xff1a; 它具有以下特性和属性&#xff0c;如&#xff1a; 常见的文字处理功能&#xff1a;它可以为用户和开发人员…

一百三十、海豚调度器——用DolphinScheduler定时调度HiveSQL任务

一、目标 用海豚调度器对Hive数仓各层数据库的SQL任务进行定时调度。比如&#xff0c;DWD层脱敏清洗表的动态插入数据、DWS层指标表的动态插入数据 二、工具版本 1、海豚调度器&#xff1a;apache-dolphinscheduler-2.0.5-bin.tar.gz 2、Hive&#xff1a;apache-hive-3.1.2…

selenium WebDriver 中的几种等待--sleep(),implicitly_wait(),WebDriverWait()

目录 强制等待:sleep() 隐式等待:implicitly_wait() 显示等待:WebDriverWait() 与until()或者until_not()方法结合使用 WebDriverWait与expected_conditions结合使用 显示等待,自定义等待条件 强制等待:sleep() import time sleep(5) #等待5秒 设置固定休眠时间&#x…

webpack打包

webpack打包 1、webpack再次打包2、webpack的入口和出口 1、webpack再次打包 背景&#xff1a;代码增加之后&#xff0c;如何打包呢&#xff1f; 1、确保在src/index.js引用和使用 2、重新执行yarn build打包命令 2、webpack的入口和出口 1、新建webpack.config.js配置文件 …

Redis的五大数据类型和各自的

- 字符串(String) string 数据结构是简单的 key-value 类型。简单动态字符串**&#xff08;simple dynamic string&#xff0c;SDS&#xff09;。相比于 C 的原生字符串&#xff0c;Redis 的 SDS 不光可以保存文本数据还可以保存二进制数据&#xff0c;并且获取字符串长度复杂度…

django框架向DRF框架演变过程详解

一、Django框架实现项目查询接口 主要知识点&#xff1a; Django框架视图函数 1、在 Django 项目中创建一个应用&#xff08;如果还没有创建&#xff09;&#xff1a; python manage.py startapp projects 2、在项目的 models.py 文件中定义项目模型 from django.db impor…

JavaWeb(5)——HTML、CSS、JS 快速入门

一、JavaScript 对象 二、JavaScript BOM对象 和 DOM对象 关于BOM主要对 Window 和 location 进行说明&#xff1a; 三、JavaScript 事件监听 事件绑定 常见事件 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8">…

OpenCv之图像形态学

目录 一、形态学 二、图像全局二值化 三、自适应阈值二值化 四、腐蚀操作 五、获取形态学卷积核 六、膨胀操作 七、开运算 八、闭运算 一、形态学 定义: 指一系列处理图像形状特征的图像处理技术形态学的基本思想是利用一种特殊的结构元(本质上就是卷积核)来测量或提取输…

【SQL】计算每个人的完成率

目录 前提任务的完成率前三名拓展&#xff1a;达梦如何去实现除法有余数拓展&#xff1a;MySQL 任务的完成率前三名 前提 达梦数据库&#xff1a; select 1/3; # 0不要求四舍五入 任务的完成率前三名 # nick_name 人名 # finishNum 当前这个人的任务完成数 # total 当前这…

STM32学习笔记(十二)丨RTC实时时钟

本篇文章包含的内容 一、计算机底层计时系统——时间戳1.1 时间戳简介1.2 GMT/UTC1.3 C语言和time.h库 二、STM32的BKP和RTC时钟2.1 BKP&#xff08;Backup Registers&#xff09;备份寄存器2.2 RTC&#xff08;Real Time Clock&#xff09;实时时钟2.2.1 RTC简介2.2.2 RTC的内…

概率论和随机过程的学习和整理20:条件概率我知道,但什么是条件期望?可用来解决递归问题

目录 1 目标问题&#xff1a; 什么是条件期望&#xff1f; 条件期望有什么用&#xff1f; 2 条件期望&#xff0c;全期望公式 3 条件期望&#xff0c;全期望公式 和 条件概率&#xff0c;全概率公式的区别和联系 3.1 公式如下 3.2 区别和联系 3.3 概率和随机过程 4 有什…

简单认识MySQL数据库索引

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、索引的概念1、简介2、作用3、索引的副作用&#xff1a;4、创建索引的原则依据5、索引的分类 二、索引的增删改查1.创建索引&#xff08;1&#xff09;创建普通索…

VoIP监控工具有什么作用

VoIP 监控工具利用思科的 IPSLA 技术生成合成流量并监控客户端体验的呼叫质量。与被动监控VoIP指标相反&#xff0c;IPSLA技术允许IT管理员主动并在潜在问题发生之前检测到它们&#xff0c;这使组织能够轻松遵守严格的SLA指标。 思科 IPSLA 技术在两台设备之间创建流量&#x…

使用semanage管理SELinux安全策略

semanage命令用于管理SELinux的策略&#xff0c;格式为“semanage [选项] [文件]”。 SELinux服务极大地提升了Linux系统的安全性&#xff0c;将用户权限牢牢地锁在笼子里。semanage命令可以设置文件、目录的策略&#xff0c;还可以管理网络端口、消息接口。 常用参数&#xf…

240. 搜索二维矩阵 II

题目描述&#xff1a; 主要思路&#xff1a; 利用矩阵中的单调性进行搜索。 class Solution { public:bool searchMatrix(vector<vector<int>>& matrix, int target) {int nmatrix.size(),mmatrix[0].size();int in-1,j0;while(i>0&&j<m){if(m…

架构训练营学习笔记:4-2 存储架构模式之复制架构

高可用的关键指标 问题&#xff1a;分为故障跟灾难。不是有了多活架构就不在用复制架构 &#xff0c;还是之前的合适原则&#xff1a;多活架构的技术复杂度 跟成本都比复制架构高。 高可用的关键指标 恢复时间目标(RecoveryTimeObjective&#xff0c;RTO)指为避免在灾难发生后…

测试基础 Android 应用测试总结

目录 启动&#xff1a; 功能介绍&#xff0c;引导图&#xff0c;流量提示等&#xff1a; 权限&#xff1a; 文件错误 屏幕旋转&#xff1a; 流量&#xff1a; 缓存&#xff08;/sdcard/data/com.your.package/cache/&#xff09;&#xff1a; 正常中断&#xff1a; 异…

jupyter notebook更换虚拟环境(内核)

jupyter notebook更换虚拟环境&#xff08;内核&#xff09; 创建一个新的虚拟环境 # stk_env 虚拟环境的名字&#xff0c;任取。 conda create -n stkenv python3.9激活虚拟环境 conda activate stkenv安装ipykernel # 为该虚拟环境&#xff0c;安装内核。 conda install -c a…

【Spring core学习三】对象装配:获取Bean对象的四种方式

目录 对象装配的四种方式 &#x1f337;1、Autowired属性注入&#xff08;使用最多&#xff09; &#x1f337;2、Setter注入 &#x1f337;3、构造函数注入 &#x1f337;4、Resource&#xff1a;另⼀种注⼊关键字 对象装配的四种方式 对象装配&#xff1a;获取bean对象也…

linux之Ubuntu系列(-)常见指令 重定向

Ubuntu 中文 版本 注意点 通过修改语言改成英文 在终端录入&#xff1a;export LANGen_US 在终端录入&#xff1a;xdg-user-dirs-gtk-update 单用户和多用户 命令格式 command [-选项] [参数] –查看命令的帮助 命令 --help man 命令 |操作键| 功能| |空格键|-显示手册的下…