---
title: "Xây dựng một công cụ đơn giản để chạy và test thời gian chạy mã nguồn C++ bằng Python"
description: "Khi code C++ mỗi lần test chúng ta cần nhập thủ công input và output, chúng ta cũng không biết thời gian chạy của code là bao nhiêu do vậy chúng ta sẽ xây dựng một công cụ bằng python giúp ta tự động làm việc này."
date: "2021-08-07"
author:
  name: "Nguyen Pham"
  role: "Xin chào. Mình thích lập trình và công nghệ. Đây là blog mình chia sẻ lại các kiến thức về lập trình, công nghệ."
  avatar: "http://0.gravatar.com/avatar/6fb61398e24046b34e13870dd6c357b9?s=128&d=mm&r=g"
category: "CPP"
tags: ["CPP", "Programming", "Python", "c++", "os", "python", "subprocess", "time"]
coverImage: "/blog/covers/xay-dung-mot-cong-cu-don-gian-de-chay-va-test-thoi-gian-chay-ma-nguon-c-bang-python.png"
featured: false
readingTime: "4 min read"
---

Khi code C++ mỗi lần test chúng ta cần nhập thủ công input và output, chúng ta cũng không biết thời gian chạy của code là bao nhiêu do vậy chúng ta sẽ xây dựng một công cụ bằng python giúp ta tự động làm việc này.

Về cơ bản chúng ta sẽ sử dụng python để chạy một số lệnh như mình chạy trong cmd vd như:

Compile C++:

```
g++ code.cpp -o tmp.exe
```

Run:

```
tmp.exe < input.txt > output.txt
```

Bắt đầu code python:

```
import os
import time
import subprocess

t = time.time()
subprocess.run(['g++','code.cpp','-o','tmp.exe'])
os.system("tmp.exe < input.txt > tmp.txt")
print(time.time()-t)

f = open('output.txt','r').read().strip();
tmp = open('tmp.txt','r').read().strip();

if(f==tmp):
    print("OK")
else:
    print("WA")
```

Đoạn code trên là chương trình python đơn giản để thực hiện việc chạy file c++.

`time.time()` Lấy thời gian hiện tại

`subprocess.run(['g++','code.cpp','-o','tmp.exe'])`  Chạy một lệch `cmd` như chương trình con.

`os.system("tmp.exe < input.txt > tmp.txt")`  chạy một lệnh `cmd` nhưng yêu cầu hệ điều hành chạy

=> chúng ta sẽ tìm hiểu sau về chúng.

Đoạn code trên cơ bản đã đáp ứng được nhưng vấn đề gặp phải là biên dịch lỗi, chạy quá thời gian thì chưa làm được. Bây giờ hãy cập nhật đoạn mã trên lên 1 level mới.

```
import os
import time
import subprocess
import compare

compileTimeout = 5
runTimeout = 5
compare.formatInput('input.txt')
compare.formatInput('dest.txt')
compileProc = subprocess.run(
    ['g++', 'code.cpp', '-o', 'tmp.exe'], timeout=compileTimeout, capture_output=True)
err = compileProc.stderr

if err != b'':
    print("Compile ERROR", err.decode())
else:
    try:
        t = time.time()
        runProc = subprocess.Popen(
            args=["tmp.exe"], stdout=subprocess.PIPE, stdin=subprocess.PIPE)
        grep_stdout = runProc.communicate(
            input=open('input.txt', 'rb').read(), timeout=runTimeout)[0]
        print(grep_stdout.decode())
        with open("output.txt", 'w', encoding='utf-8', newline='\n') as f:
            f.write(grep_stdout.decode())
        print("RUN TIME: ", (time.time()-t))
        compare.compareFile('output.txt', 'dest.txt')
    except Exception:
        print("TLE")
        runProc.kill()
```

`compare`  là file để fomat lại input. Mình sẽ để trong github ở dưới.

`subprocess.run`  Như đã giới thiệu ở trên thì thằng này sẽ chạy 1 chương trình con ngay trong chương trình chính.

- Tham số đầu tiên là mảng lệnh `['g++', 'code.cpp', '-o', 'tmp.exe']`
- `timeout` Khi quá thời gian này thì subprocess bị dừng. Tính bằng giây

`subprocess.Popen`  Thằng này cũng như  `subprocess.run`  nhưng điểm khác là nó có thể tương tác trong quá trình chạy.

`grep_stdout = runProc.communicate(input=open('input.txt', 'rb').read(), timeout=runTimeout)[0]`

sử dung  `communicate`  để truyền input vào và nhận output ra. Dữ liệu vào ở dạng binary.

Như vậy chúng ta đã xây dựng được công cụ tự động chạy code c++.

repo:<https://github.com/npv2k1/CTDLvaGT/tree/master/tool>

Một số tài liệu tham khảo:

- <https://docs.python.org/3/library/subprocess.html>
- <https://devdocs.io/python~3.8/library/subprocess#subprocess.Popen>
- <https://stackoverflow.com/questions/163542/how-do-i-pass-a-string-into-subprocess-popen-using-the-stdin-argument>
