Chi tiết cấu trúc dữ liệu bên trong Redis
cấu trúc dữ liệu
Khía cạnh đầu tiênkeo banh, từ góc độ người sử dụng. Ví dụ:
Khía cạnh này cũng là giao diện gọi API mà Redis cung cấp cho bên ngoài.
Khía cạnh thứ haikết quả bóng đá việt nam hôm nay, từ góc độ thực hiện nội bộ, thuộc về triển khai ở tầng cơ sở hơn. Ví dụ:
Cấu trúc dữ liệu http://redis.io/topics/data-types-intro Bài viết này tập trung vào việc mức thứ haikết quả bóng đá việt nam hôm nay, đó là cách Redis thực hiện các cấu trúc dữ liệu bên trong và mối liên hệ giữa các cấu trúc dữ liệu ở hai cấp độ. Cụ thể, Redis sử dụng sự kết hợp của nhiều cấu trúc dữ liệu cơ bản ở mức thứ hai để xây dựng các cấu trúc dữ liệu cao cấp hơn ở mức đầu tiên. Qua đó, chúng ta có thể hiểu rõ hơn về cách Redis tối ưu hóa hiệu suất và tổ chức dữ liệu một cách linh hoạt, giúp nó trở thành một công cụ mạnh mẽ trong xử lý dữ liệu.
Khi thảo luận về việc thực hiện nội bộ của bất kỳ hệ thống nàokeo banh, điều quan trọng là chúng ta phải xác định rõ các nguyên tắc thiết kế trước. Điều này giúp chúng ta hiểu sâu hơn về ý định thực sự đằng sau những lựa chọn thiết kế đó. Trong phần tiếp theo của bài viết này, chúng tôi sẽ tập trung vào một số khía cạnh chính sau đây:
Giải thích Chi tiết Kết cấu Dữ liệu Nội bộ của Redis
Dict là một cấu trúc dữ liệu được sử dụng để duy trì mối quan hệ ánh xạ giữa key và valuekết quả bóng đá việt nam hôm nay, tương tự như Map hoặc dictionary trong nhiều ngôn ngữ lập trình khác. Trong Redis, tất cả các mối quan hệ từ key đến value trong một database đều được duy trì thông qua một dict. Tuy nhiên, đó chỉ là một trong số rất nhiều cách mà dict được sử dụ Ví dụ, khi một Redis hash có nhiều field, nó sẽ sử dụng dict để lưu trữ dữ liệu. Hay nữa, Redis kết hợp sử dụng dict và skiplist để quản lý một tập hợp đã sắp xếp (sorted set). Những chi tiết này chúng ta sẽ bàn thêm ở phần sau. Trong bài viết này, chúng ta sẽ tập trung nghiên cứu cách thức thực hiện của dict. Trước tiên, cần hiểu rằng dict trong Redis không chỉ đơn thuần là một công cụ để ánh xạ key và value. Nó còn đóng vai trò như một cơ chế tối ưu hóa hiệu suất trong việc xử lý dữ liệu phức tạp. Khi một hash có số lượng field lớn, việc sử dụng dict giúp tăng tốc độ truy xuất dữ liệu. Điều này đặc biệt hữu ích trong môi trường mà các yêu cầu xử lý dữ liệu đòi hỏi độ chính xác cao và tốc độ nhanh chóng. Với sorted set, việc kết hợp dict và skiplist cho phép Redis cung cấp khả năng tìm kiếm và sắp xếp linh hoạt hơn, từ đó cải thiện hiệu quả hoạt động của hệ thống. Tuy vậy, để hiểu rõ hơn về cách dict hoạt động, chúng ta cần đi sâu vào các khía cạnh kỹ thuật. Đầu tiên, cần hiểu cơ chế cơ bản của dict, bao gồm cách phân bổ bộ nhớ, cách giải quyết xung đột giữa các key và cách tối ưu hóa quá trình tìm kiếm. Tất cả những yếu tố này đóng vai trò quan trọng trong việc đảm bảo Redis vận hành ổn định và hiệu quả. Chúng ta sẽ lần lượt khám phá từng khía cạnh này trong phần tiếp theo.
Dict cơ bản được thiết kế để giải quyết vấn đề tìm kiếm (Searching) trong các thuật toán. Thông thườngVSBET, cách tiếp cận để giải quyết vấn đề tìm kiếm có thể chia thành hai nhóm chính: một là dựa trên các cây cân bằng (balanced trees), và hai là dựa trên bảng băm (hash table). Những công cụ như Map hoặc dictionary mà chúng ta sử dụng hàng ngày chủ yếu được thực hiện dựa trên bảng băm. Trong trường hợp không cần dữ liệu được sắp xếp theo thứ tự và có thể duy trì xác suất xung đột băm ở mức thấp, hiệu suất tìm kiếm của phương pháp này sẽ rất cao, gần như đạt O(1), đồng thời dễ dàng triển khai và thực hiện hơn so với việc sử dụng cây. Ngoài ra, bảng băm còn giúp tối ưu hóa bộ nhớ và tốc độ xử lý nhờ khả năng ánh xạ trực tiếp giá trị đầu vào sang vị trí lưu trữ trong bộ nhớ. Điều này cho phép nó hoạt động nhanh chóng ngay cả khi lượng dữ liệu tăng lên đáng kể. Tuy nhiên, việc quản lý xung đột băm vẫn là một thách thức quan trọng cần được giải quyết để đảm bảo hiệu quả tổng thể.
thời gian phản hồi nhanh
Tiếp theo sẽ trình bày chi tiết.
Để thực hiện lại quá trình băm một cách tăng dần (incremental rehashing)kết quả bóng đá việt nam hôm nay, cấu trúc dữ liệu của dict chứa hai bảng băm. Trong quá trình này, dữ liệu sẽ được di chuyển từ bảng băm đầu tiên sang bảng băm thứ hai theo từng bước, giúp tối ưu hóa hiệu suất và đảm bảo tính ổn định trong quá trình hoạt động.
Định nghĩa mã C của dict như sau (trích từ nguồ h của Redis):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
typedef
struct
dictEntry
{
void
*
key
;
union
{
void
*
val
;
uint64_t
u64
;
int64_t
s64
;
double
d
;
}
v
;
struct
dictEntry
*
next
;
}
dictEntry
;
typedef
struct
dictType
{
unsigned
int
(
*
hashFunction
)(
const
void
*
key
);
void
*
(
*
keyDup
)(
void
*
privdata
,
const
void
*
key
);
void
*
(
*
valDup
)(
void
*
privdata
,
const
void
*
obj
);
int
(
*
keyCompare
)(
void
*
privdata
,
const
void
*
key1
,
const
void
*
key2
);
void
(
*
keyDestructor
)(
void
*
privdata
,
void
*
key
);
void
(
*
valDestructor
)(
void
*
privdata
,
void
*
obj
);
}
dictType
;
/* This is our hash table structure. Every dictionary has two of this as we
* implement incremental rehashingkeo banh, for the old to the new table. */
typedef
struct
dictht
{
dictEntry
**
table
;
unsigned
long
size
;
unsigned
long
sizemask
;
unsigned
long
used
;
}
dictht
;
typedef
struct
dict
{
dictType
*
type
;
void
*
privdata
;
dictht
ht
[
2
];
long
rehashidx
;
/* rehashing not in progress if rehashidx == -1 */
int
iterators
;
/* number of iterators currently running */
}
dict
;
Để có thể rõ ràng hơn về định nghĩa cấu trúc dữ liệu của dictkeo banh, chúng ta có thể sử dụng một biểu đồ cấu trúc để thể hiện nó. Dưới đây là hình ảnh.
Dựa trên mã nguồn và sơ đồ cấu trúc được đề cập ở trênkết quả bóng đá việt nam hôm nay, có thể dễ dàng nhận thấy cấu trúc của dict. Một dict bao gồm các thành phần sau đây: Trước hết, dict thường bắt đầu bằng một cặp dấu ngoặc nhọn {}, trong đó mỗi phần tử được phân cách bởi dấu phẩy (,). Mỗi phần tử trong dict bao gồm hai thành phần chính: key và value, được kết nối với nhau bằng dấu hai chấm (:). Điều này tạo nên một cặp giá trị duy nhấ Tiếp theo, key trong dict có thể là một chuỗi, số nguyên hoặc một số kiểu dữ liệu khác mà Python hỗ trợ, còn value có thể là bất kỳ kiểu dữ liệu nào, từ chuỗi, số cho đến cả list hay thậm chí là một dict khác. Điều này làm cho dict trở nên linh hoạt và mạnh mẽ trong việc lưu trữ thông tin. Ngoài ra, mỗi key trong dict phải là duy nhất. Nếu có hai key giống nhau được chỉ định, thì chỉ value của key cuối cùng sẽ được giữ lại. Điều này giúp tránh sự chồng chéo và đảm bảo tính nhất quán trong cấu trúc dữ liệu. Cuối cùng, dict không chỉ là một công cụ để lưu trữ dữ liệu, mà còn cung cấp nhiều phương thức hữu ích để thao tác với dữ liệu bên trong như thêm, xóa, tìm kiếm và chỉnh sửa các phần tử. Điều này làm cho dict trở thành một trong những kiểu dữ liệu quan trọng và phổ biến trong lập trình Python.
Cấu trúc dictType bao gồm một số con trỏ đến hàmkết quả bóng đá việt nam hôm nay, cho phép người gọi thực hiện các thao tác tùy chỉnh liên quan đến key và Các thao tác này bao gồm: - Tạo và quản lý việc thêm, xóa, sửa các phần tử trong dict một cách linh hoạt. - So sánh và sắp xếp key theo thứ tự mong muốn, từ đó tối ưu hóa hiệu suất tìm kiếm. - Xác định cách mã hóa hoặc giải mã key và value để phù hợp với yêu cầu của ứng dụng. - Xử lý các trường hợp đặc biệt như va chạm key hoặc giá trị null. - Tùy chỉnh cách hiển thị hoặc lưu trữ dữ liệu trong dict theo chuẩn riêng. Các con trỏ đến hàm này cung cấp khả năng tùy biến cao, cho phép dict được điều chỉnh để đáp ứng tốt nhất nhu cầu cụ thể của từng ứng dụng.
Con trỏ dữ liệu riêng tư (privdata) là một tham số được trả về cho người gọi khi một số hoạt động của dictType được kích hoạt. Đây thường là một cơ chế giúp lưu trữ thông tin bổ sung hoặc ngữ cảnh mà các hàm xử lý cần sử dụng trong quá trình thực thikết quả bóng đá việt nam hôm nay, từ đó tăng tính linh hoạt và khả năng tùy chỉnh cho cấu trúc dữ liệu.
Cần xem xét kỹ hơn cấu trúc dictht. Nó định nghĩa cấu trúc của một bảng bămkeo banh, bao gồm một số mục sau:
Trong cấu trúc dictEntrykeo banh, có chứa các thành phần k, v và con trỏ next để trỏ đến phần tử tiếp theo trong danh sách liên kết. Biến k là một con trỏ void, điều này cho phép nó có thể trỏ đến bất kỳ kiểu dữ liệu nào. Còn biến v là một union (hợp nhất), khi giá trị của nó là uint64_t, int64_t hoặc double, thì không cần phải sử dụng thêm bộ nhớ bổ sung, điều này giúp giảm thiểu tình trạng phân mảnh bộ nhớ. Tất nhiên, v cũng có thể là một con trỏ void để lưu trữ bất kỳ loại dữ liệu nào. Thêm vào đó, việc sử dụng union trong trường hợp này không chỉ tối ưu hóa không gian bộ nhớ mà còn tạo ra sự linh hoạt trong việc quản lý các loại dữ liệu khác nhau. Union cho phép cùng một vùng nhớ được sử dụng để lưu trữ nhiều kiểu dữ liệu khác nhau, tùy thuộc vào cách sử dụng cụ thể. Điều này làm cho dictEntry trở nên hiệu quả hơn trong việc xử lý các tập dữ liệu đa dạng mà không bị giới hạn bởi kích thước cố định của từng loại dữ liệu riêng lẻ.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
dict
*
dictCreate
(
dictType
*
type
,
void
*
privDataPtr
)
{
dict
*
d
=
zmalloc
(
sizeof
(
*
d
));
_dictInit
(
d
,
type
,
privDataPtr
);
return
d
;
}
int
_dictInit
(
dict
*
d
,
dictType
*
type
,
void
*
privDataPtr
)
{
_dictReset
(
&
d
->
ht
[
0
]);
_dictReset
(
&
d
->
ht
[
1
]);
d
->
type
=
type
;
d
->
privdata
=
privDataPtr
;
d
->
rehashidx
=
-
1
;
d
->
iterators
=
0
;
return
DICT_OK
;
}
static
void
_dictReset
(
dictht
*
ht
)
{
ht
->
table
=
NULL
;
ht
->
size
=
0
;
ht
->
sizemask
=
0
;
ht
->
used
=
0
;
}
Hàm dictCreate sẽ cấp phát bộ nhớ cho cấu trúc dữ liệu dict và gán giá trị khởi tạo cho các biến liên quan. Trong đókết quả bóng đá việt nam hôm nay, hai bảng băm ht[0] và ht[1] ban đầu chưa được phân bổ không gian lưu trữ, cả hai con trỏ table đều được gán giá trị NULL. Điều này có nghĩa là không gian thực sự chỉ được phân bổ khi dữ liệu đầu tiên được thêm vào. Việc trì hoãn việc phân bổ này giúp tối ưu hóa tài nguyên và tăng hiệu suất trong quá trình sử dụng.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#define dictIsRehashing(d) ((d)->rehashidx != -1)
dictEntry
*
dictFind
(
dict
*
d
,
const
void
*
key
)
{
dictEntry
*
he
;
unsigned
int
h
,
idx
,
table
;
if
(
d
->
ht
[
0
].
used
+
d
->
ht
[
1
].
used
==
0
)
return
NULL
;
/* dict is empty */
if
(
dictIsRehashing
(
d
))
_dictRehashStep
(
d
);
h
=
dictHashKey
(
d
,
key
);
for
(
table
=
0
;
table
<=
1
;
table
++
)
{
idx
=
h
&
d
->
ht
[
table
].
sizemask
;
he
=
d
->
ht
[
table
].
table
[
idx
];
while
(
he
)
{
if
(
key
==
he
->
key
||
dictCompareKeys
(
d
,
key
,
he
->
key
))
return
he
;
he
=
he
->
next
;
}
if
(
!
dictIsRehashing
(
d
))
return
NULL
;
}
return
NULL
;
}
Mã nguồn của dictFind trên đâykết quả bóng đá việt nam hôm nay, dựa trên trạng thái hiện tại của dict đang tiến hành rehashing, lần lượt thực hiện những việc sau:
Chúng ta cần xem xét kỹ hơn cách thực hiện của _dictRehashStep để rehashing từng bước.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
static
void
_dictRehashStep
(
dict
*
d
)
{
if
(
d
->
iterators
==
0
)
dictRehash
(
d
,
1
);
}
int
dictRehash
(
dict
*
d
,
int
n
)
{
int
empty_visits
=
n
*
10
;
/* Max number of empty buckets to visit. */
if
(
!
dictIsRehashing
(
d
))
return
0
;
while
(
n
--
&&
d
->
ht
[
0
].
used
!=
0
)
{
dictEntry
*
de
,
*
nextde
;
/* Note that rehashidx can't overflow as we are sure there are more
* elements because ht[0].used != 0 */
assert
(
d
->
ht
[
0
].
size
>
(
unsigned
long
)
d
->
rehashidx
);
while
(
d
->
ht
[
0
].
table
[
d
->
rehashidx
]
==
NULL
)
{
d
->
rehashidx
++
;
if
(
--
empty_visits
==
0
)
return
1
;
}
de
=
d
->
ht
[
0
].
table
[
d
->
rehashidx
];
/* Move all the keys in this bucket from the old to the new hash HT */
while
(
de
)
{
unsigned
int
h
;
nextde
=
de
->
next
;
/* Get the index in the new hash table */
h
=
dictHashKey
(
d
,
de
->
key
)
&
d
->
ht
[
1
].
sizemask
;
de
->
next
=
d
->
ht
[
1
].
table
[
h
];
d
->
ht
[
1
].
table
[
h
]
=
de
;
d
->
ht
[
0
].
used
--
;
d
->
ht
[
1
].
used
++
;
de
=
nextde
;
}
d
->
ht
[
0
].
table
[
d
->
rehashidx
]
=
NULL
;
d
->
rehashidx
++
;
}
/* Check if we already rehashed the whole table... */
if
(
d
->
ht
[
0
].
used
==
0
)
{
zfree
(
d
->
ht
[
0
].
table
);
d
->
ht
[
0
]
=
d
->
ht
[
1
];
_dictReset
(
&
d
->
ht
[
1
]);
d
->
rehashidx
=
-
1
;
return
0
;
}
/* More to rehash... */
return
1
;
}
Mỗi lần thực hiện dictRehashkeo banh, nó sẽ tiến hành ít nhất n bước tái phân tán (trừ khi toàn bộ quá trình tái phân tán kết thúc trong vòng chưa đầy n bước), và mỗi bước sẽ di chuyển từng phần tử dictEntry của một bucket (một danh sách liên kết dictEntry) từ bảng ht[0] sang bảng ht[1]. Vị trí mới của các phần tử này trên ht[1] sẽ được tính toán lại dựa trên sizemask của ht[1]. Tham số rehashidx sẽ lưu giữ vị trí hiện tại của bucket còn lại trong ht[0] mà vẫn chưa được di chuyển (các bucket đang chờ được xử lý). Quá trình này giúp tối ưu hóa việc quản lý bộ nhớ và đảm bảo rằng dữ liệu trong bảng hash luôn được sắp xếp lại một cách hợp lý khi kích thước của bảng hash thay đổi.
Khi hàm dictRehash được thực hiện và biến rehashidx đang trỏ đến một bucket trong bảng hash mà không có bất kỳ dictEntry nàoVSBET, điều đó có nghĩa là không có dữ liệu nào cần phải di chuyển. Lúc này, hệ thống sẽ cố gắng lặp qua mảng ht[0].table để tìm kiếm vị trí tiếp theo của bucket chứa dữ liệu. Nếu không tìm thấy bucket nào như vậy sau khi đã di chuyển qua nhiều lần, nó sẽ dừng lại sau tối đa n * 10 bước. Quá trình tái phân tán hash trong lần này sẽ tạm thời kết thúc. Nếu không có gì thay đổi, việc tìm kiếm các bucket chứa dữ liệu sẽ được tiếp tục trong các lần tái phân tán tiếp theo. Điều này đảm bảo rằng quá trình này không bị treo vô hạn ở một trạng thái không thể giải quyết, đồng thời duy trì hiệu suất hoạt động của hệ thống.
Cuối cùngkeo banh, nếu tất cả dữ liệu trên ht[0] đã được di chuyển sang ht[1] (tức là d->ht[0].used == 0), quá trình tái phân tán hash sẽ kết thúc. Lúc này, ht[0] sẽ có nội dung giống như ht[1], trong khi ht[1] sẽ được làm trống lại về trạng thái ban đầu, sẵn sàng cho các hoạt động tiếp theo.
Dựa trên phân tích về quá trình tái phân tán (rehashing) ở trênVSBET, ta dễ dàng nhận thấy rằng hình ảnh cấu trúc dict được trình bày trong phần trước của bài viết chính là tình huống khi rehashidx = 2. Hai bucket đầu tiên (ht[0].table[0] và ht[0].table[1]) đã được di chuyển thành công sang ht[1]. Ngoài ra, qua quá trình quan sát kỹ lưỡng, chúng ta có thể thấy rằng việc tái phân phối này không chỉ đơn thuần là việc dịch chuyển các bucket mà còn liên quan đến việc đảm bảo tính cân bằng và hiệu quả trong việc quản lý bộ nhớ. Điều này giúp hệ thống tránh được hiện tượng quá tải tại một số vị trí nhất định, từ đó nâng cao hiệu suất hoạt động tổng thể.
dictAdd chèn một cặp mới key và valueVSBET, nếu key đã tồn tại thì sẽ thất bại.
Tương tự như việc chèn một cặp key và valueVSBET, dictReplace sẽ cập nhật giá trị value nếu key đã tồn tại trong từ điển. Điều này giúp bạn dễ dàng điều chỉnh hoặc thay thế các giá trị hiện có mà không cần xóa và tạo lại toàn bộ mục.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
int
dictAdd
(
dict
*
d
,
void
*
key
,
void
*
val
)
{
dictEntry
*
entry
=
dictAddRaw
(
d
,
key
);
if
(
!
entry
)
return
DICT_ERR
;
dictSetVal
(
d
,
entry
,
val
);
return
DICT_OK
;
}
dictEntry
*
dictAddRaw
(
dict
*
d
,
void
*
key
)
{
int
index
;
dictEntry
*
entry
;
dictht
*
ht
;
if
(
dictIsRehashing
(
d
))
_dictRehashStep
(
d
);
/* Get the index of the new elementkeo banh, or -1 if
* the element already exists. */
if
((
index
=
_dictKeyIndex
(
d
,
key
))
==
-
1
)
return
NULL
;
/* Allocate the memory and store the new entry.
* Insert the element in topkết quả bóng đá việt nam hôm nay, with the assumption that in a database
* system it is more likely that recently added entries are accessed
* more frequently. */
ht
=
dictIsRehashing
(
d
)
?
&
d
->
ht
[
1
]
:
&
d
->
ht
[
0
];
entry
=
zmalloc
(
sizeof
(
*
entry
));
entry
->
next
=
ht
->
table
[
index
];
ht
->
table
[
index
]
=
entry
;
ht
->
used
++
;
/* Set the hash entry fields. */
dictSetKey
(
d
,
entry
,
key
);
return
entry
;
}
static
int
_dictKeyIndex
(
dict
*
d
,
const
void
*
key
)
{
unsigned
int
h
,
idx
,
table
;
dictEntry
*
he
;
/* Expand the hash table if needed */
if
(
_dictExpandIfNeeded
(
d
)
==
DICT_ERR
)
return
-
1
;
/* Compute the key hash value */
h
=
dictHashKey
(
d
,
key
);
for
(
table
=
0
;
table
<=
1
;
table
++
)
{
idx
=
h
&
d
->
ht
[
table
].
sizemask
;
/* Search if this slot does not already contain the given key */
he
=
d
->
ht
[
table
].
table
[
idx
];
while
(
he
)
{
if
(
key
==
he
->
key
||
dictCompareKeys
(
d
,
key
,
he
->
key
))
return
-
1
;
he
=
he
->
next
;
}
if
(
!
dictIsRehashing
(
d
))
break
;
}
return
idx
;
}
Đây là mã nguồn quan trọng của dictAdd. Chúng ta cần lưu ý một số điểm chính sau đây:
dictReplace được xây dựng dựa trên dictAddVSBET, như sau:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int
dictReplace
(
dict
*
d
,
void
*
key
,
void
*
val
)
{
dictEntry
*
entry
,
auxentry
;
/* Try to add the element. If the key
* does not exists dictAdd will suceed. */
if
(
dictAdd
(
d
,
key
,
val
)
==
DICT_OK
)
return
1
;
/* It already existsVSBET, get the entry */
entry
=
dictFind
(
d
,
key
);
/* Set the new value and free the old one. Note that it is important
* to do that in this orderkết quả bóng đá việt nam hôm nay, as the value may just be exactly the same
* as the previous one. In this context, think to reference counting,
* you want to increment (set), and then decrement (free), and not the
* reverse. */
auxentry
=
*
entry
;
dictSetVal
(
d
,
entry
,
val
);
dictFreeVal
(
d
,
&
auxentry
);
return
0
;
}
Trong trường hợp key đã tồn tạiVSBET, dictReplace sẽ đồng thời gọi đến cả dictAdd và dictFind, điều này về cơ bản giống như thực hiện hai lần quá trình tìm kiếm. Tại đây, mã nguồn của Redis chưa được tối ưu hóa hoàn toàn. Có thể nói rằng việc thực hiện cả hai hàm dictAdd và dictFind cùng lúc là không cần thiết khi key đã được xác định là đã tồn tại trong từ điển, dẫn đến việc tiêu tốn thêm tài nguyên và làm chậm hiệu suất tổng thể của hệ thống. Một cải tiến nhỏ có thể giúp giảm thiểu số lượng thao tác lặp lại và tăng tốc độ xử lý trong các trường hợp như vậy.
Mã nguồn của dictDelete ở đây được bỏ quaVSBET, xin vui lòng tham khảo dict.c. Cần chú ý một chút:
Việc triển khai của dict tương đối đơn giảnkết quả bóng đá việt nam hôm nay, bài viết này sẽ dừng lại ở đây. Ở bài viết tiếp theo, chúng ta sẽ cùng tìm hiểu về việc triển khai chuỗi động trong Redis - sds, hãy cùng đón chờ nhé.