Giải thích về trình tạo và năng suất của Python: Tiết kiệm bộ nhớ bằng các ví dụ thực tế
Trình tạo tạo ra từng giá trị một thay vì tạo toàn bộ danh sách trong bộ nhớ. Xem chính xác cách năng suất tạm dừng một chức năng, xem sự khác biệt về bộ nhớ mà chúng tôi đã đo được và xây dựng một đường truyền dữ liệu nhỏ.
- Hàm chứa
yieldtrả về trình tạo và phần thân của nó không chạy cho đến khi bạn yêu cầu một giá trị. yieldtạm dừng chức năng và giữ trạng thái cục bộ cho đến khi có yêu cầu tiếp theo.- Trình tạo sử dụng một lượng bộ nhớ nhỏ, cố định tuy nhiên chúng tạo ra nhiều giá trị.
- Một máy phát điện chỉ có thể được tiêu thụ một lần, đây là cái bẫy phổ biến nhất.
Hãy tưởng tượng tải một tệp nhật ký 10 GB vào danh sách chỉ để tìm lỗi. Chương trình của bạn có thể hết bộ nhớ trước khi tìm thấy. Trình tạo Python giải quyết vấn đề đó bằng cách tạo ra từng giá trị theo yêu cầu, để bạn có thể xử lý dữ liệu khổng lồ hoặc thậm chí vô tận mà hầu như không có bộ nhớ.
Hướng dẫn này trình bày từng bước những gì thực sự xảy ra khi máy phát điện chạy. Chúng tôi đã chạy từng ví dụ trên Python 3.13 và kết quả đầu ra là từ lần chạy đó. Sẽ giúp bạn dễ dàng làm quen với các hàm và vòng lặp mà Hướng dẫn Python dành cho người mới bắt đầu của chúng tôi đề cập đến.
Máy phát điện là gì?
Trình tạo là một loại trình vòng lặp đặc biệt mà bạn tạo bằng cách viết hàm bằng yield. Bất kỳ hàm nào có yield trong đó sẽ tự động trở thành hàm tạo và việc gọi nó sẽ cung cấp cho bạn một đối tượng trình tạo thay vì chạy mã.
def count_up(limit):
print("starting")
n = 1
while n <= limit:
yield n
n += 1
print("finished")
gen = count_up(2)
print(gen)
# <generator object count_up at 0x...>
Lưu ý rằng “bắt đầu” không được in. Việc gọi hàm chỉ tạo ra trình tạo. Chưa có gì bên trong chạy cả.
Năng suất hoạt động như thế nào, từng bước một
Mỗi lệnh gọi tới next() sẽ chạy hàm cho đến khi đạt đến yield, trả lại giá trị đó và cố định tại chỗ. Cuộc gọi tiếp theo sẽ tiếp tục ngay sau dòng đó, với mọi biến cục bộ còn nguyên.
print(next(gen))
# starting
# 1
print(next(gen))
# 2
next(gen)
# finished
# StopIteration
Theo dõi đầu ra một cách cẩn thận. “bắt đầu” chỉ xuất hiện ở next() đầu tiên. Ở lần thứ hai, việc thực thi tiếp tục từ nơi nó dừng, vì vậy n vẫn khả dụng và trở thành 2. Ở lần thứ ba, vòng lặp kết thúc, in “hoàn thành”, hàm rơi ra khỏi điểm cuối và Python tăng StopIteration để báo hiệu rằng không còn gì.
Bạn hiếm khi gọi next() cho mình. Vòng lặp for thực hiện việc đó cho bạn và xử lý StopIteration một cách lặng lẽ, cũng như list(), sum() và các chức năng tương tự:
print(list(count_up(3)))
# starting
# finished
# [1, 2, 3]
năng suất so với lợi nhuận
| Khía cạnh | trở về |
năng suất |
|---|---|---|
| Nó làm gì | Kết thúc chức năng | Tạm dừng chức năng |
| Giá trị được tạo ra | Một kết quả | Một loạt, mỗi lần một |
| Tiểu bang địa phương | Bị loại bỏ | Bảo toàn giữa các giá trị |
| Khi mã chạy | Ngay khi được gọi | Chỉ khi một giá trị được yêu cầu |
| Bộ nhớ cho nhiều giá trị | Phải nắm giữ tất cả | Giữ từng cái một |
Sự chậm trễ này được gọi là đánh giá lười biếng: các giá trị chỉ được xử lý khi cần thiết. Một đơn giản return bên trong trình tạo chỉ đơn giản là kết thúc nó, kích hoạt StopIteration.
Sự khác biệt về bộ nhớ, được đo
Chúng tôi đã so sánh danh sách một triệu ô vuông với một trình tạo tương đương, sử dụng sys.getsizeof:
import sys
squares_list = [n * n for n in range(1_000_000)]
squares_gen = (n * n for n in range(1_000_000))
print(sys.getsizeof(squares_list), sys.getsizeof(squares_gen))
# 8448728 200
Cấu trúc riêng của danh sách chiếm khoảng 8,4 MB, trong khi trình tạo chỉ chiếm 200 byte trên hệ thống của chúng tôi. Khoảng cách thực sự thậm chí còn lớn hơn, vì getsizeof không tính các đối tượng nguyên bên trong danh sách. Kích thước của trình tạo cũng giữ nguyên cho một tỷ mục vì nó chỉ lưu trữ trạng thái hiện tại chứ không lưu trữ kết quả.
Tuy nhiên, có một sự đánh đổi. Một danh sách có thể được sử dụng lại, lập chỉ mục và đo lường bằng len(). Một máy phát điện không cung cấp những thứ này. Nếu bạn cần truy cập ngẫu nhiên hoặc bạn sẽ lặp lại nhiều lần trên một lượng nhỏ dữ liệu thì danh sách sẽ đơn giản hơn. Xem hướng dẫn của chúng tôi về Danh sách Python so với bộ dữ liệu so với tập hợp để biết thêm về các loại đó.
biểu thức trình tạo
Đối với những trường hợp đơn giản, bạn không cần hàm. Biểu thức trình tạo trông giống như danh sách hiểu với dấu ngoặc tròn thay cho dấu ngoặc vuông:
squares = [n * n for n in range(5)] # builds a list now
squares = (n * n for n in range(5)) # produces values on demand
print(sum(n * n for n in range(5)))
# 30
Khi biểu thức trình tạo là đối số duy nhất cho hàm, như trong sum(), bạn có thể bỏ qua các dấu ngoặc phụ. Đây là một thói quen gọn gàng để tính tổng trên dữ liệu lớn vì không có danh sách tạm thời nào được tạo.
Xây dựng đường dẫn dữ liệu
Đây là nơi máy phát điện thực sự tỏa sáng. Các máy phát điện nhỏ có thể được xâu chuỗi để mỗi mục đi qua từng bước, từng bước một:
def read_lines(lines):
for line in lines:
yield line.strip()
def only_errors(lines):
for line in lines:
if line.startswith("ERROR"):
yield line
def messages(lines):
for line in lines:
yield line.split(" ", 1)[1]
log = ["INFO started\n", "ERROR db down\n",
"ERROR disk full\n", "INFO stopped\n"]
print(list(messages(only_errors(read_lines(log)))))
# ['db down', 'disk full']
Mỗi bước thực hiện một công việc nhỏ và có thể tự kiểm tra. Trong sử dụng thực tế, hãy hoán đổi danh sách mẫu lấy một tệp đang mở, vì các đối tượng tệp có thể được đọc từng dòng, như hướng dẫn của chúng tôi về xử lý tệp Python trình bày. Ngay cả một bản ghi nhiều gigabyte sau đó cũng sẽ được xử lý với rất ít bộ nhớ.
Mẹo: Đường dẫn không hoạt động cho đến khi có thứ gì đó tiêu thụ nó. Xây dựng chuỗi là ngay lập tức. Quá trình xử lý chỉ xảy ra khi bạn lặp qua trình tạo cuối cùng hoặc gói nó trong một lệnh gọi như list().
Chuỗi vô hạn
Một danh sách không thể là vô hạn, nhưng một trình tạo thì có thể, bởi vì nó chỉ tính giá trị tiếp theo. Sử dụng itertools.islice để lấy bao nhiêu tùy ý:
import itertools
def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
print(list(itertools.islice(fibonacci(), 8)))
# [0, 1, 1, 2, 3, 5, 8, 13]
Tuy nhiên, hãy cẩn thận: việc gọi list(fibonacci()) không giới hạn sẽ chạy cho đến khi hết bộ nhớ. Mẫu tương tự phù hợp với trình tạo ID, vòng bỏ phiếu và kết quả API được phân trang, trong đó bạn chỉ tìm nạp trang tiếp theo khi trang hiện tại hết.
sản lượng từ và lô
yield from chuyển sang một vòng lặp khác, giúp bạn tiết kiệm được một vòng lặp lồng nhau:
def chain_all(*groups):
for group in groups:
yield from group
print(list(chain_all([1, 2], (3, 4))))
# [1, 2, 3, 4]
Một mẫu rất thực tế là chia dữ liệu thành các lô có kích thước cố định, chẳng hạn như để chèn một nghìn hàng vào cơ sở dữ liệu cùng một lúc:
def batches(items, size):
batch = []
for item in items:
batch.append(item)
if len(batch) == size:
yield batch
batch = []
if batch:
yield batch
print(list(batches(range(7), 3)))
# [[0, 1, 2], [3, 4, 5], [6]]
if batch cuối cùng đảm bảo rằng nhóm còn sót lại nhỏ hơn không bị mất. Python 3.12 trở lên cũng bao gồm itertools.batched, thực hiện công việc tương tự.
gửi, đóng và dọn dẹp
Máy phát điện cũng có thể nhận được giá trị. send() tiếp tục trình tạo và giá trị trở thành kết quả của biểu thức yield. Bạn phải gọi next() lần đầu tiên để đạt được yield đầu tiên:
def running_total():
total = 0
while True:
value = yield total
total += value
t = running_total()
next(t)
print(t.send(10), t.send(5))
# 10 15
Hầu hết mọi người hiếm khi cần điều này. Một mối quan tâm phổ biến hơn là dọn dẹp. Nếu bạn dừng sớm, khối finally vẫn chạy khi đóng trình tạo:
def tracked():
try:
yield 1
yield 2
finally:
print("cleanup ran")
tr = tracked()
next(tr)
tr.close()
# cleanup ran
Pytest sử dụng chính ý tưởng này: một thiết bị cố định với yield sẽ tiến hành dọn dẹp sau đó, như hướng dẫn pytest của chúng tôi minh họa. Tương tự như vậy, trình trang trí contextmanager của thư viện chuẩn sẽ biến trình tạo thành khối with.
Máy phát điện trong lớp học
Viết một phương thức __iter__ làm trình tạo là cách dễ nhất để làm cho lớp của riêng bạn có thể lặp lại được. Một phần thưởng là mỗi vòng lặp có một trình tạo mới, do đó đối tượng có thể được lặp đi lặp lại:
class Countdown:
def __init__(self, start):
self.start = start
def __iter__(self):
n = self.start
while n > 0:
yield n
n -= 1
c = Countdown(3)
print(list(c), list(c))
# [3, 2, 1] [3, 2, 1]
Khi nào nên sử dụng máy phát điện
| Sử dụng máy phát điện khi | Sử dụng danh sách khi |
|---|---|
| Dữ liệu lớn hoặc kích thước của nó không xác định | Dữ liệu nhỏ và vừa với bộ nhớ |
| Bạn xử lý các mục một lần, theo thứ tự | Bạn lặp lại nhiều lần |
| Bạn có thể dừng lại sớm | Bạn cần len(), lập chỉ mục hoặc cắt |
| Bạn đang đọc một luồng hoặc tập tin | Bạn cần sắp xếp hoặc đảo ngược dữ liệu |
| Bạn đang xây dựng một đường ống | Sự đơn giản quan trọng hơn trí nhớ |
Nhìn chung, máy phát điện không phải lúc nào cũng nhanh hơn. Nếu bạn sử dụng mọi giá trị thì tổng công việc sẽ tương tự và việc hiểu danh sách thậm chí có thể nhanh hơn đối với dữ liệu nhỏ vì nó tốn ít chi phí hơn cho mỗi mục. Lợi ích chính là sử dụng bộ nhớ và nhận được kết quả đầu tiên sớm hơn.
Những lỗi thường gặp
Tái sử dụng máy phát điện đã cạn kiệt
Điều này thu hút gần như tất cả mọi người tại một số điểm. Một máy phát điện nhớ rằng nó đã hoàn thành:
g = count_up(2)
print(list(g), list(g))
# [1, 2] []
Cuộc gọi thứ hai nhận được một danh sách trống không có lỗi nào cả. Gọi lại hàm để có trình tạo mới hoặc sử dụng cách tiếp cận lớp được trình bày ở trên.
Mong đợi mã sẽ chạy ngay lập tức
def noisy():
print("body runs")
yield 1
n = noisy() # nothing is printed
print(next(n)) # body runs, then 1
Việc kiểm tra đối số ở đầu trình tạo không chạy cho đến next() đầu tiên, do đó, lỗi có thể xuất hiện khác xa với lệnh gọi gây ra chúng.
Các bẫy khác
- Gọi
len()hoặc lập chỉ mục. Trình tạo không hỗ trợ và tăngTypeError. - Đóng tệp quá sớm. Việc trả lại trình tạo từ bên trong khối
withcó thể có nghĩa là tệp sẽ đóng trước khi bất kỳ dòng nào được đọc. Đặtyieldbên trong khốiwith. - Gói mọi thứ trong
list(). Điều đó sẽ làm mất đi lợi ích về bộ nhớ. - Sử dụng một danh sách cho dữ liệu nhỏ. Danh sách đơn giản thường rõ ràng hơn.
Lời kết
Trình tạo là một chức năng có thể tạm dừng. Ý tưởng đó mang lại cho bạn mức sử dụng bộ nhớ thấp, trình tự vô tận và đường ống sạch sẽ. Để áp dụng nó vào thực tế, hãy tìm một vị trí trong mã của bạn để xây dựng một danh sách lớn chỉ để lặp lại nó một lần và biến nó thành một trình tạo. Sau đó thử nối hai trình tạo nhỏ lại với nhau trên một tệp nhật ký thực.
Câu hỏi thường gặp
Năng suất làm gì trong Python?
năng suất tạo ra một giá trị và tạm dừng hàm, giữ nguyên các biến cục bộ của nó. Hàm sẽ tiếp tục lại từ cùng một điểm khi giá trị tiếp theo được yêu cầu.
Sự khác biệt giữa trình tạo và danh sách là gì?
Một danh sách lưu trữ tất cả các giá trị của nó trong bộ nhớ cùng một lúc. Trình tạo tính toán từng giá trị theo yêu cầu, sử dụng ít bộ nhớ và thường chỉ có thể được sử dụng một lần.
Sự khác biệt giữa trình vòng lặp và trình tạo là gì?
Mỗi máy phát điện là một trình vòng lặp. Trình tạo đơn giản là cách dễ nhất để viết một trình tạo, vì Python tạo các phương thức __iter__ và __next__ cho bạn.
Bạn có thể lặp qua một máy phát điện hai lần không?
Không. Một khi đã cạn kiệt, nó sẽ không mang lại kết quả gì nữa mà không gây ra lỗi. Tạo một trình tạo mới bằng cách gọi lại hàm hoặc lưu kết quả vào danh sách.
Máy phát điện có nhanh hơn danh sách không?
Không phải lúc nào cũng vậy. Chúng sử dụng ít bộ nhớ hơn và cung cấp kết quả đầu tiên sớm hơn, nhưng việc hiểu danh sách có thể nhanh hơn một chút khi bạn sử dụng toàn bộ lượng dữ liệu nhỏ.
Tiếp tục học hỏi
Cần trợ giúp về kiểm tra, WordPress hoặc SEO?
Chúng tôi giúp các nhóm phát triển phần mềm tốt hơn và phát triển trang web của họ. Hãy cho chúng tôi biết bạn đang làm gì và chúng tôi sẽ đề xuất bước tiếp theo rõ ràng.
Thêm hướng dẫn về thử nghiệm, AI và phát triển hiện đại
Bạn thích bài viết này? Chọn một chủ đề và chuyển ngay sang phần hướng dẫn mới nhất của chúng tôi.
Giải thích về ảo giác AI: Tại sao các mô hình ngôn ngữ lại tạo nên mọi thứ và cách giảm thiểu nó
Ảo giác AI đã giải thích: chúng là gì, tại sao mô hình ngôn ngữ tạo ra chúng, các loại phổ biến, cách giảm thiểu chúng bằng cách căn cứ và nhắc nhở …
Đọc bài viết →DevOpsGiải thích về các biến môi trường: Tệp .env, bí mật và cấu hình được thực hiện đúng
Các biến môi trường được giải thích bằng các ví dụ Python mà chúng tôi đã chạy: đọc và thiết lập chúng, tại sao mọi giá trị đều là một chuỗi, tệp .e…
Đọc bài viết →Phát triển phần mềmGiải thích về giới hạn tỷ lệ API: Thuật toán, tiêu đề và xử lý lỗi 429
Giới hạn tốc độ API được giải thích bằng mô phỏng mà chúng tôi đã chạy: nhóm mã thông báo, cửa sổ cố định, cửa sổ trượt, 429 phản hồi, tiêu đề giới …
Đọc bài viết →Tự động hóa kiểm thửChế giễu bằng Python: unittest.mock, patch và những sai lầm khiến bài kiểm tra nói dối
Mô phỏng bằng Python với unittest.mock, đã được thử nghiệm: Mock và return_value, side_effect, vá lỗi nơi sử dụng tên, thông số kỹ thuật và thông số…
Đọc bài viết →Kiểm thử phần mềmGiải thích về phạm vi bảo hiểm của mã: Phạm vi tuyến so với chi nhánh và ý nghĩa thực sự 100%
Phạm vi bảo hiểm mã được giải thích bằng cách chạy phạm vi bảo hiểm thực tế: phạm vi bảo hiểm dòng, chi nhánh và điều kiện, đọc báo cáo, lý do tại s…
Đọc bài viết →Cơ sở dữ liệu & SQLDELETE vs TRUNCATE vs DROP trong SQL: Sự khác biệt, khôi phục và thời điểm sử dụng mỗi loại
DELETE vs TRUNCATE vs DROP được giải thích bằng SQL đã được thử nghiệm: mỗi loại loại bỏ, khôi phục, kích hoạt, đặt lại danh tính, tốc độ và Postgre…
Đọc bài viết →Cơ sở dữ liệu & SQLGiải thích về Chế độ xem SQL: Tạo, sử dụng và tránh những cạm bẫy, kèm theo ví dụ
Chế độ xem SQL được giải thích bằng các truy vấn chúng tôi đã chạy: tạo chế độ xem, kết quả trực tiếp, ẩn cột, hiệu suất, chế độ xem có thể cập nhật…
Đọc bài viết →Phát triển phần mềmGiao diện TypeScript so với loại: Sự khác biệt thực sự, được thử nghiệm bằng trình biên dịch
Giao diện TypeScript so với loại, được kiểm tra bằng trình biên dịch thực: cả hai có thể làm gì, chỉ một người có thể làm gì, hợp nhất khai báo, mở …
Đọc bài viết →Phát triển phần mềmGiải thích về Python *args và **kwargs: Hàm linh hoạt với ví dụ rõ ràng
Python *args và **kwargs được giải thích bằng mã chúng tôi đã chạy: đóng gói và giải nén, thứ tự tham số, đối số chỉ từ khóa và chỉ vị trí, trình tr…
Đọc bài viết →Phát triển phần mềmHàm Lambda của Python: Cú pháp, cách sử dụng thực tế và khi nào không nên sử dụng chúng
Các hàm lambda của Python được giải thích bằng mã chúng tôi đã chạy: cú pháp, sắp xếp bằng khóa, bản đồ và bộ lọc, các phần đóng, bẫy liên kết muộn …
Đọc bài viết →Trí tuệ nhân tạoĐại lý AI là gì? Cách chúng hoạt động, với vòng lặp tác nhân đơn giản, bạn có thể chạy
Tác nhân AI là gì? Hướng dẫn đơn giản về vòng lặp tác nhân, công cụ, bộ nhớ và lan can, với một vòng lặp Python nhỏ mà chúng tôi đã chạy, những rủi …
Đọc bài viết →DevOpsGiám sát và Khả năng quan sát: Sự khác biệt thực sự, với nhật ký, số liệu và dấu vết
Giải thích về giám sát và khả năng quan sát: lỗi đã biết và chưa biết, nhật ký, số liệu và dấu vết, hướng dẫn về sự cố thanh toán, tín hiệu vàng, Op…
Đọc bài viết →DevOpsDocker Volumes vs Bind Mounts: Duy trì dữ liệu vùng chứa đúng cách
Giải thích về khối lượng Docker và liên kết gắn kết: tại sao dữ liệu vùng chứa biến mất, khối lượng được đặt tên, liên kết gắn kết, tmpfs, ví dụ về …
Đọc bài viết →Tự động hóa kiểm thửTDD vs BDD: Key Differences, One Feature Built Both Ways and When to Use Each
TDD và BDD được giải thích bằng một tính năng giảm giá được xây dựng theo cả hai cách: tái cấu trúc màu đỏ-xanh với mã chúng tôi đã chạy, kịch bản C…
Đọc bài viết →Kiểm thử phần mềmKiểm tra chấp nhận của người dùng (UAT): Quy trình, danh sách kiểm tra và ví dụ thực tế
Giải thích về thử nghiệm chấp nhận của người dùng: ai chạy nó, nó khác với QA như thế nào, quy trình bảy bước, mẫu trường hợp thử nghiệm UAT, danh s…
Đọc bài viết →Cơ sở dữ liệu & SQLGiải thích về các giá trị NULL của SQL: IS NULL, COALESCE, NULLIF và những cái bẫy cần tránh
Các giá trị SQL NULL được giải thích bằng các truy vấn chúng tôi đã chạy: logic ba giá trị, IS NULL, COALESCE, NULLIF, cách tổng hợp, kết hợp và sắp…
Đọc bài viết →Cơ sở dữ liệu & SQLCâu lệnh SQL CASE WHEN: Cú pháp, ví dụ thực tế và các lỗi thường gặp
TRƯỜNG HỢP SQL KHI được giải thích bằng các truy vấn mà chúng tôi đã chạy: các biểu mẫu đơn giản và được tìm kiếm, thứ tự điều kiện, các thủ thuật S…
Đọc bài viết →Phát triển phần mềmJWT là gì? Mã thông báo Web JSON được giải thích bằng một ví dụ hoạt động
JWT là gì? Mã thông báo Web JSON đã giải thích: ba phần, mã thông báo được xây dựng và giả mạo trong mã chúng tôi đã chạy, JWT so với phiên, lưu trữ…
Đọc bài viết →Phát triển phần mềmGiải thích về vòng lặp sự kiện JavaScript: Ngăn xếp cuộc gọi, Microtask và bộ hẹn giờ kèm ví dụ
Vòng lặp sự kiện JavaScript được giải thích bằng mã chúng tôi đã chạy: ngăn xếp cuộc gọi, hàng đợi tác vụ và vi nhiệm, tại sao setTimeout 0 không di…
Đọc bài viết →Phát triển phần mềmGiải thích về trình tạo và năng suất của Python: Tiết kiệm bộ nhớ bằng các ví dụ thực tế
Trình tạo và lợi nhuận Python được giải thích bằng mã chúng tôi đã chạy: cách chúng tạm dừng và tiếp tục, đo mức tiết kiệm bộ nhớ, quy trình, chuỗi …
Đọc bài viết →Trí tuệ nhân tạoNhúng là gì? Giải thích sự tương đồng về vectơ và Cosine một cách đơn giản
nhúng là gì? Hướng dẫn bằng ngôn ngữ đơn giản về vectơ, độ tương tự cosine và tìm kiếm ngữ nghĩa, với một ví dụ nhỏ mà chúng tôi đã chạy, các cách s…
Đọc bài viết →DevOpsTriển khai Blue-Green và Canary: Sự khác biệt, sự đánh đổi và cách lựa chọn
Giải thích về triển khai Blue-green và Canary: cách hoạt động của từng loại, chi phí, rủi ro và khôi phục, nhóm người dùng ổn định mà chúng tôi đã t…
Đọc bài viết →Tự động hóa kiểm thửKiểm tra không ổn định: Nguyên nhân gây ra chúng và cách khắc phục chúng vĩnh viễn
Các thử nghiệm không ổn định được giải thích bằng các bản demo mà chúng tôi đã chạy: nguyên nhân chính, cách xác nhận và chẩn đoán nguyên nhân, cách…
Đọc bài viết →Kiểm thử phần mềmKiểm tra tải và kiểm tra căng thẳng: Sự khác biệt, số liệu và ví dụ về k6
Giải thích về thử nghiệm tải và thử nghiệm căng thẳng: mỗi thử nghiệm chứng minh điều gì, thử nghiệm tăng đột biến và ngâm, số liệu quan trọng, lý d…
Đọc bài viết →Kiểm thử phần mềmTrường hợp thử nghiệm và kịch bản thử nghiệm: Sự khác biệt chính, ví dụ và thời điểm sử dụng từng trường hợp
Giải thích trường hợp kiểm thử và kịch bản kiểm thử: định nghĩa rõ ràng, bảng cạnh nhau, một tính năng đặt lại mật khẩu được lấy từ các tình huống n…
Đọc bài viết →Cơ sở dữ liệu & SQLTối ưu hóa truy vấn SQL: Đọc kế hoạch thực thi và sửa các truy vấn chậm, có tính thời gian
Đã thử nghiệm tối ưu hóa truy vấn SQL trên một triệu hàng: đọc kế hoạch thực hiện, thêm chỉ mục phù hợp, sửa các bộ lọc không thể mở rộng, sử dụng c…
Đọc bài viết →Cơ sở dữ liệu & SQLSQL UNION và UNION ALL: Sự khác biệt, ví dụ và hiệu suất đã được kiểm tra
SQL UNION và UNION ALL được giải thích bằng các truy vấn chúng tôi đã chạy: trùng lặp, cả hai quy tắc đều tuân theo, lỗi dữ liệu thực, hiệu suất đượ…
Đọc bài viết →Phát triển phần mềmHướng dẫn API tìm nạp JavaScript: GET, POST, Xử lý lỗi và hết thời gian chờ
Hướng dẫn API tìm nạp JavaScript đã được thử nghiệm trên máy chủ cục bộ: GET và POST, tại sao 404 không gửi, trình trợ giúp có thể sử dụng lại, chuỗ…
Đọc bài viết →Phát triển phần mềmXử lý tệp Python: Đọc, ghi, CSV, JSON và pathlib kèm ví dụ
Việc xử lý tệp Python được giải thích bằng mã chúng tôi đã chạy: chế độ mở, với, đọc tệp lớn, CSV, JSON, pathlib, tệp nhị phân, ghi an toàn, xử lý l…
Đọc bài viết →Phát triển phần mềmCác lớp và đối tượng Python: Hướng dẫn OOP với các ví dụ thực tế
Các lớp và đối tượng Python được giải thích bằng mã mà chúng tôi đã chạy: __init__, các phương thức, thuộc tính lớp và phiên bản, tính kế thừa, thuộ…
Đọc bài viết →Trí tuệ nhân tạoMô hình ngôn ngữ lớn là gì? LLM hoạt động như thế nào, được giải thích mà không cường điệu hóa
Mô hình ngôn ngữ lớn là gì? LLM được giải thích bằng ngôn ngữ đơn giản: mã thông báo, phần nhúng, sự chú ý, đào tạo, cửa sổ nhiệt độ và ngữ cảnh, mộ…
Đọc bài viết →DevOpsCác lệnh Linux cho người mới bắt đầu: Hướng dẫn thiết bị đầu cuối cần thiết kèm ví dụ
Các lệnh Linux dành cho người mới bắt đầu, được nhóm theo tác vụ: điều hướng, tệp, xem nhật ký, grep, đường dẫn, quyền, quy trình và lưu trữ, cùng v…
Đọc bài viết →Tự động hóa kiểm thửSelenium vs Nhà viết kịch: Sự khác biệt chính, So sánh mã và nên chọn cái nào
Selenium và Playwright được so sánh: kiến trúc, chờ đợi, hỗ trợ trình duyệt và ngôn ngữ, gỡ lỗi, kiểm tra giống nhau ở cả hai công cụ, lời khuyên di…
Đọc bài viết →Kiểm thử phần mềmPhân vùng tương đương: Giải thích kỹ thuật thiết kế thử nghiệm bằng các ví dụ đã thực hiện
Giải thích về phân vùng tương đương: cách tìm các phân vùng hợp lệ và không hợp lệ, các ví dụ hoạt động theo độ tuổi, mật khẩu và phiếu giảm giá, cá…
Đọc bài viết →Kiểm thử phần mềmMức độ nghiêm trọng và mức độ ưu tiên trong kiểm thử phần mềm: Sự khác biệt, Ma trận và ví dụ thực tế
Giải thích về mức độ nghiêm trọng và mức độ ưu tiên trong kiểm thử phần mềm: định nghĩa rõ ràng, ma trận bốn chiều với các ví dụ, thang đo cấp độ, a…
Đọc bài viết →Cơ sở dữ liệu & SQLHướng dẫn về truy vấn con SQL: Các loại, truy vấn con tương quan và TỒN TẠI kèm ví dụ
Hướng dẫn về truy vấn con SQL với các truy vấn chúng tôi đã chạy: truy vấn con vô hướng, IN, FROM và SELECT, truy vấn con tương quan, EXISTS, bẫy và…
Đọc bài viết →Cơ sở dữ liệu & SQLGiải thích về giao dịch SQL và ACID: Các mức CAM KẾT, ROLLBACK và Cô lập
Các giao dịch SQL và ACID được giải thích bằng chuyển khoản ngân hàng mà chúng tôi đã thực hiện: CAM KẾT, ROLLBACK, điểm lưu trữ, khóa, mức cách ly,…
Đọc bài viết →Phát triển phần mềmGit merge vs rebase: khác biệt, ví dụ và khi nào dùng cái nào
Git merge vs rebase được giải thích bằng đầu ra log thực tế, bảng so sánh, quy tắc vàng của rebase và quy trình làm việc nhóm an toàn.
Đọc bài viết →Phát triển phần mềmList comprehension trong Python: cú pháp, ví dụ và khi nào nên tránh
List comprehension trong Python: cú pháp, lọc dữ liệu, if-else, vòng lặp lồng nhau, thời gian đo thực tế và khi nào vòng lặp for thông thường tốt hơn.
Đọc bài viết →Cơ sở dữ liệu & SQLGiải thích SQL JOIN kèm ví dụ (Inner, Left, Right, Full)
Hiểu SQL JOIN từng bước với bảng và truy vấn mẫu: INNER, LEFT, RIGHT, FULL, CROSS và SELF, cùng lỗi thường gặp và mẹo hiệu năng.
Đọc bài viết →