Twitter-高性能hash_map

0、Redis真正学习前自准备 0、Redis真正学习前自准备 引言 在Web应用发展的初期,那时关系型数据库受到了较为广泛的关注和应用,原因是因为那时候Web站点基本上访问和并发不高、交互也较少。而在后来,随着访问量的提升,使用关系型数据库的Web站点多多少少都开始在性能上出现了一些瓶颈,而瓶颈的源头一般是在磁盘的I/O上。而随着互联网技术的进一步发展,各种类型的应用层出不穷,这导致在当今云计算、大数据盛行的时代,对性能有了更多的需求,主要体现在以下四个方面: 1、低延迟的读写速度: 应用快速地反应能极大地提升用户的满意度 2、支撑海量 阅读详情

学习twitter的高性能散列表源码:


个人认为Twitter散列表的优点:
1、使用C宏定义实现C++泛型的思想;
2、散列函数冲突小;
3、使用bitmap思想,标志位占用空间小;
4、自动扩展容量,判断扩容的条件;


个人认为Twitter散列表的缺点:
1、值的类型都用指针指向,对于值类型是简单整型有指针占用空间的缺点;(虽然值类型是基本整型的情况较少,但是可以通过宏进行值类型是基本类型进行选定)


1、使用C的#define写类似于C++泛型的代码;

#define KHASH_INIT2(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
   __KHASH_TYPE(name, khkey_t, khval_t)                        \
   __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)

name:散列表的名称可以自定义;

khval_t:散列表的值类型可以自定义,在散列表里是指针;

khkey_t:散列表的key可以不可以自定义,但是可以选择32位或者64位的key;


__hash_func:散列函数可以选择,提供很多种散列函数;

/* --- BEGIN OF HASH FUNCTIONS --- */

/*! @function
  @abstract     Integer hash function
  @param  key   The integer [khint32_t]
  @return       The hash value [khint_t]
 */
#define kh_int_hash_func(key) (khint32_t)(key)
/*! @function
  @abstract     Integer comparison function
 */
#define kh_int_hash_equal(a, b) ((a) == (b))
/*! @function
  @abstract     64-bit integer hash function
  @param  key   The integer [khint64_t]
  @return       The hash value [khint_t]
 */
#define kh_int64_hash_func(key) (khint32_t)((key)>>33^(key)^(key)<<11)
/*! @function
  @abstract     64-bit integer comparison function
 */
#define kh_int64_hash_equal(a, b) ((a) == (b))
/*! @function
  @abstract     const char* hash function
  @param  s     Pointer to a null terminated string
  @return       The hash value
 */
static kh_inline khint_t __ac_X31_hash_string(const char *s)
{
   khint_t h = (khint_t)*s;
   if (h) for (++s ; *s; ++s) h = (h << 5) - h + (khint_t)*s;
   return h;
}
/*! @function
  @abstract     Another interface to const char* hash function
  @param  key   Pointer to a null terminated string [const char*]
  @return       The hash value [khint_t]
 */
#define kh_str_hash_func(key) __ac_X31_hash_string(key)
/*! @function
  @abstract     Const char* comparison function
 */
#define kh_str_hash_equal(a, b) (strcmp(a, b) == 0)

static kh_inline khint_t __ac_Wang_hash(khint_t key)
{
    key += ~(key << 15);
    key ^=  (key >> 10);
    key +=  (key << 3);
    key ^=  (key >> 6);
    key += ~(key << 11);
    key ^=  (key >> 16);
    return key;
}
#define kh_int_hash_func2(key) __ac_Wang_hash((khint_t)key)

__hash_equal:散列里面的判断key相等,因为只有32和64的整数,所以不可以选择;

下面的定义类型结构体:

__KHASH_TYPE(name, khkey_t, khval_t)
#define __KHASH_TYPE(name, khkey_t, khval_t) \
   typedef struct kh_##name##_s { \
      khint_t n_buckets, size, n_occupied, upper_bound; \
      khint32_t *flags; \
      khkey_t *keys; \
      khval_t *vals; \
   } kh_##name##_t;

下面的定义name和khval_t的函数:

__KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
#define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
   SCOPE kh_##name##_t *kh_init_##name(void) {                    \
      return (kh_##name##_t*)kcalloc(1, sizeof(kh_##name##_t));      \
   }                                                  \
   SCOPE void kh_destroy_##name(kh_##name##_t *h)                 \
   {                                                  \
      if (h) {                                        \
         kfree((void *)h->keys); kfree(h->flags);              \
         kfree((void *)h->vals);                            \
         kfree(h);                                       \
      }                                               \
   }                                                  \
   SCOPE void kh_clear_##name(kh_##name##_t *h)                \
   {                                                  \
      if (h && h->flags) {                               \
         memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \
         h->size = h->n_occupied = 0;                       \
      }                                               \
   }                                                  \
   SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key)  \
   {                                                  \
      if (h->n_buckets) {                                   \
         khint_t k, i, last, mask, step = 0; \
         mask = h->n_buckets - 1;                           \
         k = __hash_func(key); i = k & mask;                   \
         last = i; \
         while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
            i = (i + (++step)) & mask; \
            if (i == last) return h->n_buckets;                \
         }                                            \
         return __ac_iseither(h->flags, i)? h->n_buckets : i;     \
      } else return 0;                                   \
   }                                                  \
   SCOPE int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \
   { /* This function uses 0.25*n_buckets bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. */ \
      khint32_t *new_flags = 0;                             \
      khint_t j = 1;                                     \
      {                                               \
         kroundup32(new_n_buckets);                            \
         if (new_n_buckets < 4) new_n_buckets = 4;             \
         if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0; /* requested size is too small */ \
         else { /* hash table size to be changed (shrink or expand); rehash */ \
            new_flags = (khint32_t*)kmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t));  \
            if (!new_flags) return -1;                      \
            memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
            if (h->n_buckets < new_n_buckets) { /* expand */      \
               khkey_t *new_keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
               if (!new_keys) { kfree(new_flags); return -1; }    \
               h->keys = new_keys;                          \
               if (kh_is_map) {                          \
                  khval_t *new_vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
                  if (!new_vals) { kfree(new_flags); return -1; } \
                  h->vals = new_vals;                       \
               }                                      \
            } /* otherwise shrink */                        \
         }                                            \
      }                                               \
      if (j) { /* rehashing is needed */                       \
         for (j = 0; j != h->n_buckets; ++j) {                 \
            if (__ac_iseither(h->flags, j) == 0) {             \
               khkey_t key = h->keys[j];                    \
               khval_t val;                              \
               khint_t new_mask;                         \
               new_mask = new_n_buckets - 1;                   \
               if (kh_is_map) val = h->vals[j];             \
               __ac_set_isdel_true(h->flags, j);               \
               while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \
                  khint_t k, i, step = 0; \
                  k = __hash_func(key);                     \
                  i = k & new_mask;                      \
                  while (!__ac_isempty(new_flags, i)) i = (i + (++step)) & new_mask; \
                  __ac_set_isempty_false(new_flags, i);        \
                  if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { /* kick out the existing element */ \
                     { khkey_t tmp = h->keys[i]; h->keys[i] = key; key = tmp; } \
                     if (kh_is_map) { khval_t tmp = h->vals[i]; h->vals[i] = val; val = tmp; } \
                     __ac_set_isdel_true(h->flags, i); /* mark it as deleted in the old hash table */ \
                  } else { /* write the element and jump out of the loop */ \
                     h->keys[i] = key;                   \
                     if (kh_is_map) h->vals[i] = val;       \
                     break;                              \
                  }                                   \
               }                                      \
            }                                         \
         }                                            \
         if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \
            h->keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
            if (kh_is_map) h->vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
         }                                            \
         kfree(h->flags); /* free the working space */            \
         h->flags = new_flags;                              \
         h->n_buckets = new_n_buckets;                      \
         h->n_occupied = h->size;                           \
         h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \
      }                                               \
      return 0;                                          \
   }                                                  \
   SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) \
   {                                                  \
      khint_t x;                                         \
      if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \
         if (h->n_buckets > (h->size<<1)) {                    \
            if (kh_resize_##name(h, h->n_buckets - 1) < 0) { /* clear "deleted" elements */ \
               *ret = -1; return h->n_buckets;                 \
            }                                         \
         } else if (kh_resize_##name(h, h->n_buckets + 1) < 0) { /* expand the hash table */ \
            *ret = -1; return h->n_buckets;                    \
         }                                            \
      } /* TODO: to implement automatically shrinking; resize() already support shrinking */ \
      {                                               \
         khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \
         x = site = h->n_buckets; k = __hash_func(key); i = k & mask; \
         if (__ac_isempty(h->flags, i)) x = i; /* for speed up */ \
         else {                                          \
            last = i; \
            while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
               if (__ac_isdel(h->flags, i)) site = i;          \
               i = (i + (++step)) & mask; \
               if (i == last) { x = site; break; }             \
            }                                         \
            if (x == h->n_buckets) {                        \
               if (__ac_isempty(h->flags, i) && site != h->n_buckets) x = site; \
               else x = i;                               \
            }                                         \
         }                                            \
      }                                               \
      if (__ac_isempty(h->flags, x)) { /* not present at all */      \
         h->keys[x] = key;                               \
         __ac_set_isboth_false(h->flags, x);                   \
         ++h->size; ++h->n_occupied;                           \
         *ret = 1;                                       \
      } else if (__ac_isdel(h->flags, x)) { /* deleted */            \
         h->keys[x] = key;                               \
         __ac_set_isboth_false(h->flags, x);                   \
         ++h->size;                                      \
         *ret = 2;                                       \
      } else *ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \
      return x;                                          \
   }                                                  \
   SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x)          \
   {                                                  \
      if (x != h->n_buckets && !__ac_iseither(h->flags, x)) {        \
         __ac_set_isdel_true(h->flags, x);                     \
         --h->size;                                      \
      }                                               \
   }

2、散列表支持动态扩展桶的数目;

在put函数里面,会判断,如果满足

h->n_occupied >= h->upper_bound

则通过resize进行扩展:

khint_t x;
if (h->n_occupied >= h->upper_bound) { /* update the hash table */ 
 if (h->n_buckets > (h->size<<1)) { 
    if (kh_resize_##name(h, h->n_buckets - 1) < 0) { /* clear "deleted" elements */ 
       *ret = -1; return h->n_buckets;                 
    }                                         
 } else if (kh_resize_##name(h, h->n_buckets + 1) < 0) { /* expand the hash table */ 
    *ret = -1; return h->n_buckets;                
 }                                          
}

3、使用bitmap作为桶有没有被放置的标记;

khint32_t *flags;//散列表里的bit标志,bitmap

加上一系列对于bitmap的快速位操作,进行判断空、某个位置是否存在key等

#define __ac_isempty(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&2)
#define __ac_isdel(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&1)
#define __ac_iseither(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&3)
#define __ac_set_isdel_false(flag, i) (flag[i>>4]&=~(1ul<<((i&0xfU)<<1)))
#define __ac_set_isempty_false(flag, i) (flag[i>>4]&=~(2ul<<((i&0xfU)<<1)))
#define __ac_set_isboth_false(flag, i) (flag[i>>4]&=~(3ul<<((i&0xfU)<<1)))
#define __ac_set_isdel_true(flag, i) (flag[i>>4]|=1ul<<((i&0xfU)<<1))

4、定义一些工具函数

//函数声明
#define __KHASH_PROTOTYPES(name, khkey_t, khval_t)                \
   extern kh_##name##_t *kh_init_##name(void);                    \
   extern void kh_destroy_##name(kh_##name##_t *h);               \
   extern void kh_clear_##name(kh_##name##_t *h);                 \
   extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key);   \
   extern int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \
   extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \
   extern void kh_del_##name(kh_##name##_t *h, khint_t x);
//方便使用的宏定义,可以通过name和语义进行调用;

/*!
  @abstract Type of the hash table.
  @param  name  Name of the hash table [symbol]
 */
#define khash_t(name) kh_##name##_t

/*! @function
  @abstract     Initiate a hash table.
  @param  name  Name of the hash table [symbol]
  @return       Pointer to the hash table [khash_t(name)*]
 */
#define kh_init(name) kh_init_##name()

/*! @function
  @abstract     Destroy a hash table.
  @param  name  Name of the hash table [symbol]
  @param  h     Pointer to the hash table [khash_t(name)*]
 */
#define kh_destroy(name, h) kh_destroy_##name(h)

/*! @function
  @abstract     Reset a hash table without deallocating memory.
  @param  name  Name of the hash table [symbol]
  @param  h     Pointer to the hash table [khash_t(name)*]
 */
#define kh_clear(name, h) kh_clear_##name(h)

/*! @function
  @abstract     Resize a hash table.
  @param  name  Name of the hash table [symbol]
  @param  h     Pointer to the hash table [khash_t(name)*]
  @param  s     New size [khint_t]
 */
#define kh_resize(name, h, s) kh_resize_##name(h, s)

/*! @function
  @abstract     Insert a key to the hash table.
  @param  name  Name of the hash table [symbol]
  @param  h     Pointer to the hash table [khash_t(name)*]
  @param  k     Key [type of keys]
  @param  r     Extra return code: -1 if the operation failed;
                0 if the key is present in the hash table;
                1 if the bucket is empty (never used); 2 if the element in
            the bucket has been deleted [int*]
  @return       Iterator to the inserted element [khint_t]
 */
#define kh_put(name, h, k, r) kh_put_##name(h, k, r)

/*! @function
  @abstract     Retrieve a key from the hash table.
  @param  name  Name of the hash table [symbol]
  @param  h     Pointer to the hash table [khash_t(name)*]
  @param  k     Key [type of keys]
  @return       Iterator to the found element, or kh_end(h) if the element is absent [khint_t]
 */
#define kh_get(name, h, k) kh_get_##name(h, k)

/*! @function
  @abstract     Remove a key from the hash table.
  @param  name  Name of the hash table [symbol]
  @param  h     Pointer to the hash table [khash_t(name)*]
  @param  k     Iterator to the element to be deleted [khint_t]
 */
#define kh_del(name, h, k) kh_del_##name(h, k)

/*! @function
  @abstract     Test whether a bucket contains data.
  @param  h     Pointer to the hash table [khash_t(name)*]
  @param  x     Iterator to the bucket [khint_t]
  @return       1 if containing data; 0 otherwise [int]
 */
#define kh_exist(h, x) (!__ac_iseither((h)->flags, (x)))

/*! @function
  @abstract     Get key given an iterator
  @param  h     Pointer to the hash table [khash_t(name)*]
  @param  x     Iterator to the bucket [khint_t]
  @return       Key [type of keys]
 */
#define kh_key(h, x) ((h)->keys[x])

/*! @function
  @abstract     Get value given an iterator
  @param  h     Pointer to the hash table [khash_t(name)*]
  @param  x     Iterator to the bucket [khint_t]
  @return       Value [type of values]
  @discussion   For hash sets, calling this results in segfault.
 */
#define kh_val(h, x) ((h)->vals[x])

/*! @function
  @abstract     Alias of kh_val()
 */
#define kh_value(h, x) ((h)->vals[x])

/*! @function
  @abstract     Get the start iterator
  @param  h     Pointer to the hash table [khash_t(name)*]
  @return       The start iterator [khint_t]
 */
#define kh_begin(h) (khint_t)(0)

/*! @function
  @abstract     Get the end iterator
  @param  h     Pointer to the hash table [khash_t(name)*]
  @return       The end iterator [khint_t]
 */
#define kh_end(h) ((h)->n_buckets)

/*! @function
  @abstract     Get the number of elements in the hash table
  @param  h     Pointer to the hash table [khash_t(name)*]
  @return       Number of elements in the hash table [khint_t]
 */
#define kh_size(h) ((h)->size)

/*! @function
  @abstract     Get the number of buckets in the hash table
  @param  h     Pointer to the hash table [khash_t(name)*]
  @return       Number of buckets in the hash table [khint_t]
 */
#define kh_n_buckets(h) ((h)->n_buckets)

/*! @function
  @abstract     Iterate over the entries in the hash table
  @param  h     Pointer to the hash table [khash_t(name)*]
  @param  kvar  Variable to which key will be assigned
  @param  vvar  Variable to which value will be assigned
  @param  code  Block of code to execute
 */
#define kh_foreach(h, kvar, vvar, code) { khint_t __i;      \
   for (__i = kh_begin(h); __i != kh_end(h); ++__i) {    \
      if (!kh_exist(h,__i)) continue;                 \
      (kvar) = kh_key(h,__i);                      \
      (vvar) = kh_val(h,__i);                      \
      code;                                  \
   } }

/*! @function
  @abstract     Iterate over the values in the hash table
  @param  h     Pointer to the hash table [khash_t(name)*]
  @param  vvar  Variable to which value will be assigned
  @param  code  Block of code to execute
 */
#define kh_foreach_value(h, vvar, code) { khint_t __i;      \
   for (__i = kh_begin(h); __i != kh_end(h); ++__i) {    \
      if (!kh_exist(h,__i)) continue;                 \
      (vvar) = kh_val(h,__i);                      \
      code;                                  \
   } }

/* More conenient interfaces */

/*! @function
  @abstract     Instantiate a hash set containing integer keys
  @param  name  Name of the hash table [symbol]
 */
#define KHASH_SET_INIT_INT(name)                            \
   KHASH_INIT(name, khint32_t, char, 0, kh_int_hash_func, kh_int_hash_equal)

/*! @function
  @abstract     Instantiate a hash map containing integer keys
  @param  name  Name of the hash table [symbol]
  @param  khval_t  Type of values [type]
 */
#define KHASH_MAP_INIT_INT(name, khval_t)                      \
   KHASH_INIT(name, khint32_t, khval_t, 1, kh_int_hash_func, kh_int_hash_equal)

/*! @function
  @abstract     Instantiate a hash map containing 64-bit integer keys
  @param  name  Name of the hash table [symbol]
 */
#define KHASH_SET_INIT_INT64(name)                             \
   KHASH_INIT(name, khint64_t, char, 0, kh_int64_hash_func, kh_int64_hash_equal)

/*! @function
  @abstract     Instantiate a hash map containing 64-bit integer keys
  @param  name  Name of the hash table [symbol]
  @param  khval_t  Type of values [type]
 */
#define KHASH_MAP_INIT_INT64(name, khval_t)                       \
   KHASH_INIT(name, khint64_t, khval_t, 1, kh_int64_hash_func, kh_int64_hash_equal)

typedef const char *kh_cstr_t;
/*! @function
  @abstract     Instantiate a hash map containing const char* keys
  @param  name  Name of the hash table [symbol]
 */
#define KHASH_SET_INIT_STR(name)                            \
   KHASH_INIT(name, kh_cstr_t, char, 0, kh_str_hash_func, kh_str_hash_equal)

/*! @function
  @abstract     Instantiate a hash map containing const char* keys
  @param  name  Name of the hash table [symbol]
  @param  khval_t  Type of values [type]
 */
#define KHASH_MAP_INIT_STR(name, khval_t)                      \
   KHASH_INIT(name, kh_cstr_t, khval_t, 1, kh_str_hash_func, kh_str_hash_equal)

使用散列表

KHASH_MAP_INIT_INT(32, char)


void test_khash_map()
{
	int ret, is_missing;
	khiter_t k;
	khash_t(32)* h = kh_init(32);
	k = kh_put(32, h, 5, &ret);
	kh_value(h, k) = 10;
	k = kh_get(32, h, 10);
	is_missing = (k == kh_end(h));
	k = kh_get(32, h, 5);
	kh_del(32, h, k);
	for (k = kh_begin(h); k != kh_end(h); ++k)
		if (kh_exist(h, k)) kh_value(h, k) = 1;
	kh_destroy(32, h);
	return;
}
Redis应用场景 国内外三个不同领域巨头分享的Redis实战经验及使用场景 随着应用对高性能需求的增加,NoSQL逐渐在各大名企的系统架构中生根发芽。这里我们将为大家分享社交巨头新浪微博、传媒巨头Viacom及图片分享领域佼佼者Pinterest带来的Redis实践,首先我们看新浪微博 @启盼cobain的Redis实战经验分享: 一、新浪微博:史上最大的Redis集群 Tape is Dead,Disk is Tape,Flash is Disk,RAM Locality is King. — Jim Gra 阅读详情

相关推荐

【信息科学与工程学】计算机科学与自动化——第三百零三篇 Java高性能指南03

编号类型领域编程语言问题函数/算法名称函数算法的数学分析及逐步推理思考求解的数学方程式及参数列表及参数的数值范围及常量函数的数据结构与调用的指令列表程序完整的可执行代码及编译器配置及资源需求关联知识401LMAX Disruptor详解高性能Java (JDK 8+)深入理解Disruptor无锁队列的原理与使用Disruptor (RingBuffer + Sequence Barrier)数学方程: 大小 , 使用 配合内存屏障。参数:,。推理:Disruptor通过预分配事件槽位、无锁CAS更新Se

weixin_49199313的博客 255

Tweepsmap应用:轻松获悉Twitter粉丝的地理分布

想知道你的Twitter粉丝分布在世界的哪些地方么?Tweepsmap帮你轻松实现。   Tweepsmap是一款通过分析用户粉丝的个人资料收集他们的所在地,并以Google地图的形式呈现出来的应用。   通过Twitter账户授权该应用后(该授权过程可能需要花费几分钟),用户便可在Google地图上看到遍布世界各地的蓝色标记。还可放大地图,查看粉丝数最多的国家或城市。   该应...

java开发指南博客 【转载】 300

模型参考自适应控制(MRAC):让PID参数动态优化

本文深入解析模型参考自适应控制(MRAC)技术,它通过实时调整PID参数,使控制系统能自动适应系统特性变化和外部干扰。文章详细介绍了MRAC的工作原理、数学基础,并提供了用C语言实现的实战代码示例,帮助工程师解决传统PID控制在非线性、时变系统中参数整定繁琐的难题。

tequila的博客 902

深度解析twitter-cldr-rb自定义格式化器:国际化扩展与架构设计实践

在Ruby国际化开发领域,twitter-cldr-rb作为ICU标准的Ruby实现,为开发者提供了强大的本地化数据处理能力。然而,当项目需要处理特定领域的格式化需求或集成自定义数据源时,标准格式化器往往无法满足复杂业务场景。本文将深入探讨twitter-cldr-rb自定义格式化器的架构设计、实现原理及最佳实践,帮助开发者构建可扩展、高性能的国际化解决方案。 ## 问题域分析:标准格式化器的局

gitblog_00982的博客 741

平台跳跃游戏中的自动寻路,与地图导航扩展

平台游戏:主要的游戏方式是在2D平面上使用各种方式在悬浮平台上进行移动和穿过各种障碍。 现如的平台游戏中的平台特性与种类是很多的,像马里奥(FC)的单向支撑不可穿透的,或魂斗罗(FC)单向支撑可穿透的… \ 超级玛丽 魂斗罗 空洞骑士 蔚蓝 本博文 支撑 上 上 上 左、上、右 上 穿透 无 上、下 无 上(部分) 上下 所以本文主要以向上支撑并上下穿透的平台特性来进行实现 需求分析 在关卡设计后,地形的数据需要自动识别 地形中的平台可上下穿透移动,并可向上站立 平台的移动路..

MOV的博客 3062

SATA硬件电路设计实战:从接口规范到高速布线技巧

本文深入探讨了SATA硬件电路设计的核心要点与实战技巧。从接口物理电气规范、AC耦合电容与阻抗控制等基础,到FPGA/SoC高速收发器选型配置,再到应对6Gbps高速信号的PCB布局布线艺术,系统性地解析了SATA电路设计中的关键挑战与解决方案,助力工程师规避常见陷阱,实现稳定可靠的存储接口设计。

tech5的博客 528

Redis是什么?看这一篇就够了

最近在学redis,看到了这篇写的据详细的文章,在此分享给大家。不做任何商业用途。转载请标注 原文地址:https://www.grapecity.com.cn/ 引言 在Web应用发展的初期,那时关系型数据库受到了较为广泛的关注和应用,原因是因为那时候Web站点基本上访问和并发不高、交互也较少。而在后来,随着访问量的提升,使用关系型数据库的Web站点多多少少都开始在性能上出现了一些瓶颈,而瓶颈的源头一般是在磁盘的I/O上。而随着互联网技术的进一步发展,各种类型的应用层出不穷,这导致在当今云计算、大数据

weixin_44096353的博客 330

redis简介

Redis是现在最受欢迎的NoSQL数据库之一,Redis是一个使用ANSI C编写的开源、包含多种数据结构、支持网络、基于内存、可选持久性的键值对存储数据库,其具备如下特性: 基于内存运行,性能高效 支持分布式,理论上可以无限扩展 key-value存储系统 开源的使用ANSI C语言编写、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API 相比于其他数据库类型,Redis具备的特点是: C/S通讯模型 单进程单线程模型

weixin_57763462的博客 137

锂电池寿命预测 | Python实现基于LSTM长短期记忆神经网络的锂电池寿命预测

锂电池寿命预测 | Python实现基于LSTM长短期记忆神经网络的锂电池寿命预测

算法如诗的博客 1900

ROM和RAM在单片机程序运行理解

ROM和RAM是电子设备中两种核心存储组件,主要区别在于:ROM用于长期存储系统程序、用户文件等固定数据,断电后数据不丢失,但写入速度较慢;RAM则用于临时存储运行中的程序和数据,读写速度快但断电后数据会清空。在单片机中,ROM存储程序代码和常量,RAM存储运行时的变量和数据。两者协同工作,ROM如同"永久档案库"保存必要信息,RAM则像"临时工作台"支持高速运算,共同确保设备正常运行。

qq_37999850的博客 1618

xiaoai-patch 小爱音箱开源固件改造:完整刷机步骤、决策清单与救砖方法

xiaoai-patch 是一套面向小爱音箱的开源固件改造工具,把原厂闭源系统替换为 MPD、Snapcast、Shairport-Sync 等开源音频组件,并支持 Porcupine 唤醒词与 Whisper 语音识别。它适合有一线 Linux 基础、愿意拆机刷机的用户,不适合想继续用米家 APP 的人。 [![小爱音箱LX06主板 开源固件刷机改造对象](https://raw.gitcod

gitblog_01004的博客 467

【AgentScope 2.0】01-不搭 demo,直接解剖一个生产级 Agent 平台:loser-agent 全链路地图

本文介绍生产级Agent平台loser-agent的完整请求旅程,从用户发消息到返回结果共七站:入口鉴权、灰度路由、Agent装配、模型路由、工具执行、持久化与流式响应。课程以真实源码为线索,深入剖析每一步实现逻辑,涵盖灰度发布、权限控制、HITL审批、多模态处理、状态持久化等核心能力。强调框架仅负责Agent运行时语义,平台自建管理请求生命周期中所有非框架部分,适合Java后端开发者系统掌握Agent工程化落地。

loser.with.m的博客 724

redis

Redis是什么?看这一篇就够了 本文由葡萄城技术团队编撰并首发 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。 引言 在Web应用发展的初期,那时关系型数据库受到了较为广泛的关注和应用,原因是因为那时候Web站点基本上访问和并发不高、交互也较少。而在后来,随着访问量的提升,使用关系型数据库的Web站点多多少少都开始在性能上出现了一些瓶颈,而瓶颈的源头一般是在磁盘的I/O上。而随着互联网技术的进一步发展,各种类型的应用层出不穷,这导致在当今云计算、大数

weixin_50770886的博客 210

储能电池管理系统介绍(一)

介绍储能BMS的架构以及各模块功能

manjixingkong1234的专栏 1914

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

MAS 免费激活 Windows 与 Office 指南

MAS(Microsoft Activation Scripts)是一个开源激活脚本,支持 Windows 8.1/10/11 与 Office,内置 HWID、Ohook、TSforge、Online KMS 4 种激活方式,还带状态检查、版本变更与故障排查工具,照着本文 3 步即可上手。 ## 没有它的时候,激活有多麻烦 Windows 或 Office 未激活时,桌面右下角挂着水印,部分

gitblog_00054的博客 525

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

redis入门

redis入门学习

m0_49260486的博客 308

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

Redis常见应用场景之拙见

前言 Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合),并 在 2.8.9 版本添加了 HyperLogLog 结构。如何根据不同的应用场景选择不同的数据类型呢? Redis中的发布订阅,事务功能,又怎么应用于业务中呢? Redis中的布隆过滤器用过吗? 带着这些疑问,下文将逐条解答。 string Strings 数据结构是简单的key-value类型,value其实不仅是String,也可以是数字.常用

qq_28908085的博客 351

Redis的最常被问到知识点总结

1.什么是redis?    Redis 是一个基于内存的高性能key-value数据库。 2.Reids的特点      Redis本质上是一个Key-Value类型的内存数据库,很像memcached,整个数据库统统加载在内存当中进行操作,定期通过异步操作把数据库数据flush到硬盘上进行保存。因为是纯内存操作,Redis的性能非常出色,每秒可以处理超过 10万次读写操作,是...

qq_42221826的博客 305

Theine:基于自适应 W-TinyLFU 的高性能泛型内存缓存实战指南(vendor 内嵌源码深度解析)

Theine 是一个受 Caffeine 启发、以 Go 泛型实现的进程内高性能缓存库,核心亮点是自适应 W-TinyLFU 淘汰策略与分层时间轮(hierarchical timer wheel)过期机制。本指南以其在仓库中 vendor 的内嵌源码与 README 为基础,带你从零上手 Builder/Client API、Loading 缓存、缓存持久化与混合二级缓存,并深入源码底层理解其命

gitblog_01128的博客 345

从零到生产:构建企业级Heron流处理系统的实战指南

在当今数据驱动的商业环境中,实时流处理已成为企业数字化转型的核心能力。面对海量数据流和严苛的延迟要求,传统批处理系统往往力不从心。Apache Heron作为Twitter开源的分布式流处理引擎,以其卓越的性能和可靠性,正在成为企业构建实时数据处理平台的首选方案。 ## 为什么选择Heron:企业级流处理的三大挑战 ### 挑战一:高吞吐与低延迟的平衡困境 传统流处理系统往往在高吞吐量和低延

gitblog_00470的博客 389

DeFi-Developer-Road-Map 实战指南:从 DLT 基础到链上安全的 DeFi 开发者技能树与工具链全解析

本篇技术指南以 DeFi-Developer-Road-Map 仓库的意大利语版路线图文档([translations/README_it.md](https://link.gitcode.com/i/143422e1e096260444f64a6fb5ac7647))为主体骨架,系统拆解一条面向 DeFi 与区块链开发者的完整学习路径:从分布式账本(DLT)与密码学基础出发,依次覆盖智能合约与代

gitblog_00240的博客 339

如何3步彻底移除 Windows Defender(附动手前备份清单)

# 如何3步彻底移除 Windows Defender(附动手前备份清单) windows-defender-remover 是一个开源工具,能在 Windows 8.x、Windows 10 各版本和 Windows 11 上移除 Windows Defender:停用杀毒引擎与驱动、移除 Windows 安全中心界面,并清理相关计划任务和 SmartScreen 组件。适合想因误报、资源占用

gitblog_00551的博客 415

Redis基础知识

Redis基本操作一、简介二、下载安装三 、Redis的基本操作四、Redis数据类型 一、简介 1. 问题现象 海量用户。 高并发。 2. 罪魁祸首——关系型数据库 性能瓶颈:磁盘IO性能低下。 扩展瓶颈:数据关系复杂,扩展性差,不便于大规模集群。 3. 解决思路 降低磁盘IO次数,越低越好——内存存储。 去除数据间关系,越简单越好——不存储关系,仅存储数据。 4. Nosql NoSQL:即 Not-Only SQL( 泛指非关系型的数据库),作为关系型数据库的补充。 作用:应对基于海量用

残影的博客 529
上一篇: #pragma pack结构体对齐
下一篇: 并发数据结构的目的和设计指南理解学习
KPer_Yang
博客等级 码龄4年 281粉丝 181原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KPer_Yang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值