起因 # 最近在学 Stanford CS336(Language Modeling from Scratch),做 tokenizer 作业时,第一次在测试代码里见到了 pytest.mark.xfail。
具体是这段:
1@pytest.mark.xfail( 2 reason="Tokenizer.encode is expected to take more memory than allotted (1MB)." 3) 4def test_encode_memory_usage(): 5 """ 6 We expect this test to fail, since Tokenizer.encode is not expected to be memory efficient. 7 """ 8 tokenizer = get_tokenizer_from_vocab_merges_path( 9 vocab_path=VOCAB_PATH, 10 merges_path=MERGES_PATH, 11 ) 12 with open(FIXTURES_PATH / "tinystories_sample_5M.txt") as f: 13 contents = f.read() 14 _ = _encode(tokenizer, contents) 我当时第一反应是困惑:既然作者明确知道 encode 会超过 1MB,为什么不直接写成 assert memory > 1MB?或者干脆删掉?为什么要提交一个「预期会失败」的测试?
接口 # 一个ABC,后面会继承这个类做各种实现
clean up function # 代码比较好懂,唯一让我感到疑惑的是 clean up function 这部分
1 2 // FIXME: 不太理解为什么需要很多个clean up function 3 // Cleanup functions are stored in a single-linked list. 4 // The list's head node is inlined in the iterator. 5 struct CleanupNode { 6 // True if the node is not used. Only head nodes might be unused. 7 bool IsEmpty() const { return function == nullptr; } 8 // Invokes the cleanup function. 9 void Run() { 10 assert(function != nullptr); 11 (*function)(arg1, arg2); 12 } 13 14 // The head node is used if the function pointer is not null. 15 CleanupFunction function; 16 void* arg1; 17 void* arg2; 18 CleanupNode* next; 19 }; 20 CleanupNode cleanup_head_; 21}; 从 table/iterator.cc 的析构函数中,可以看到在iterator析构的时候会依次调用多个clean up function