# LoopTick
一个简单的 Python 循环耗时测量工具。
## 安装
```bash
pip install looptick
```
本地安装
```bash
git clone https://github.com/DBinK/LoopTick
pip install -e .
```
## 使用示例
### 测量每个循环用时
常规方式
```python
from looptick import LoopTick
import time
looptick = LoopTick()
# 常规调用方式
for i in range(5):
diff = looptick.tick()
print(f"第 {i} 次循环耗时: {diff * looptick.NS2MS:.6f} ms")
time.sleep(0.01)
print(f"总耗时: {looptick.total_sec:.6f} 秒")
print(f"平均耗时: {looptick.average_ms:.6f} ms")
# 或者用更精简的语法
for i in range(5):
diff = looptick() # 直接调用 __call__() 方法, 免去书写 tick()
print(f"第 {i} 次循环耗时: {diff * looptick.NS2MS:.6f} ms")
time.sleep(0.01)
```
使用上下文方式
```python
from looptick import LoopTick
import time
with LoopTick() as looptick:
with LoopTick() as looptick:
for i in range(5):
diff = looptick.tick()
print(f"第 {i} 次循环耗时: {diff * looptick.NS2MS:.6f} ms")
diff = looptick.tick()
print(f"第 {i} 次循环耗时: {diff * looptick.NS2MS:.6f} ms")
time.sleep(0.01)
```
输出结果示例:
```bash
(LoopTick) PS C:\IT\LoopTick> & C:\IT\LoopTick\.venv\Scripts\python.exe c:/IT/LoopTick/examples/with_usage.py
第 0 次循环耗时: 0.000000 ms
第 1 次循环耗时: 10.829900 ms
第 2 次循环耗时: 16.055800 ms
第 3 次循环耗时: 14.013400 ms
第 4 次循环耗时: 15.587100 ms
总耗时: 0.056486 秒
平均耗时: 14.121550 ms
```
### 测量行间代码用时
```python
from looptick import LoopTick
import time
def stage1():
time.sleep(0.02) # 模拟 I/O 操作
def stage2():
time.sleep(0.05) # 模拟复杂计算
def stage3():
time.sleep(0.01) # 模拟轻量处理
# 使用多阶段测量
linetick = LoopTick()
for i in range(3): # 模拟 1000 次循环
start = linetick.tick() # 第一次调用, 返回一个极小值 (0.000_001)
# 完成一次循环后, 返回上一次循环的 mid2 -> start 的用时
# 一般我们不关心 start 变量的值, 仅表示测量开始
stage1()
stage2()
mid1 = linetick.tick() # 返回 start —> mid1 的用时
stage3()
mid2 = linetick.tick() # 返回 mid1 —> mid2 的用时
print(f"\n第 {i} 次循环")
print(f"stage1() + stage2() 耗时: {mid1 * linetick.NS2MS:.2f} ms")
print(f"stage3() 耗时: {mid2 * linetick.NS2MS:.2f} ms")
print(f"本循环总耗时: {(mid1 + mid2) * linetick.NS2MS:.2f} ms")
print(f"\n循环任务总耗时: {linetick.total_sec:.6f} 秒")
```
输出结果示例:
```bash
(LoopTick) PS C:\IT\LoopTick> & C:\IT\LoopTick\.venv\Scripts\python.exe c:/IT/LoopTick/examples/lines_usage.py
第 0 次循环
stage1() + stage2() 耗时: 93.78 ms
stage3() 耗时: 15.10 ms
本循环总耗时: 108.88 ms
第 1 次循环
stage1() + stage2() 耗时: 89.86 ms
stage3() 耗时: 15.11 ms
本循环总耗时: 104.97 ms
第 2 次循环
stage1() + stage2() 耗时: 89.71 ms
stage3() 耗时: 15.01 ms
本循环总耗时: 104.72 ms
循环任务总耗时: 0.319596 秒
```
### 进阶用法: 多 Tick 测量
```python
from looptick import LoopTick
import time
def stage1():
time.sleep(0.02) # 模拟 I/O 操作
def stage2():
time.sleep(0.05) # 模拟复杂计算
def stage3():
time.sleep(0.03) # 模拟轻量处理
# 使用多阶段测量 + 单独循环测量
linetick = LoopTick()
looptick = LoopTick()
for i in range(3): # 模拟 1000 次循环
loop_ns = looptick.tick() # 单独使用一个对象测量循环时间
start = linetick.tick() # 第一次调用, 返回一个极小值 (0.000_001)
# 完成一次循环后, 返回上一次循环的 mid2 -> start 的用时
# 一般我们不关心 start 变量的值, 仅表示测量开始
stage1()
stage2()
mid1 = linetick.tick() # 返回 start —> mid1 的用时
stage3()
mid2 = linetick.tick() # 返回 mid1 —> mid2 的用时
print(f"\n第 {i} 次循环")
print(f"stage1() + stage2() 耗时: {mid1 * linetick.NS2MS:.2f} ms")
print(f"stage3() 耗时: {mid2 * linetick.NS2MS:.2f} ms")
print(f"linetick 对象测量的循环耗时: {(mid1 + mid2) * linetick.NS2MS:.2f} ms")
print(f"looptick 对象测量的循环耗时: {loop_ns * linetick.NS2MS:.2f} ms")
print(f"\nlinetick 对象测量的循环任务总耗时: {linetick.total_sec:.6f} 秒")
print(f"looptick 对象测量的循环任务总耗时: {looptick.total_sec:.6f} 秒")
print(f"looptick 测量的每次循环平均耗时: {looptick.average_ms:.6f} ms")
# 注意: looptick 对象会少一次循环的计时, 因为在第一次调用时只能返回一个极小值 (0.000_001)
```
输出结果示例:
```bash
(LoopTick) PS C:\IT\LoopTick> & C:\IT\LoopTick\.venv\Scripts\python.exe c:/IT/LoopTick/examples/multi_tick_usage.py
第 0 次循环
stage1() + stage2() 耗时: 94.48 ms
stage3() 耗时: 45.04 ms
linetick 对象测量的循环耗时: 139.52 ms
looptick 对象测量的循环耗时: 0.00 ms
第 1 次循环
stage1() + stage2() 耗时: 89.68 ms
stage3() 耗时: 44.96 ms
linetick 对象测量的循环耗时: 134.65 ms
looptick 对象测量的循环耗时: 140.12 ms
第 2 次循环
stage1() + stage2() 耗时: 89.43 ms
stage3() 耗时: 44.88 ms
linetick 对象测量的循环耗时: 134.31 ms
looptick 对象测量的循环耗时: 135.23 ms
linetick 对象测量的循环任务总耗时: 0.409659 秒
looptick 对象测量的循环任务总耗时: 0.275349 秒
looptick 测量的每次循环平均耗时: 137.674650 ms
```
## 已知问题
- [] 在第一次调用时只能返回一个极小值 (0.000_001)
Raw data
{
"_id": null,
"home_page": null,
"name": "looptick",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": null,
"keywords": "benchmark, loop, performance, profiling, timer",
"author": null,
"author_email": "DBinK <DBinKv1d@Gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/8d/71/682cd0c190d7020ba50cb97a10b67d101728702e4eda16f8dff132eb430c/looptick-0.1.1.tar.gz",
"platform": null,
"description": "# LoopTick\n\n\u4e00\u4e2a\u7b80\u5355\u7684 Python \u5faa\u73af\u8017\u65f6\u6d4b\u91cf\u5de5\u5177\u3002\n\n## \u5b89\u88c5\n```bash\npip install looptick\n```\n\u672c\u5730\u5b89\u88c5\n```bash\ngit clone https://github.com/DBinK/LoopTick\npip install -e .\n```\n\n## \u4f7f\u7528\u793a\u4f8b\n\n### \u6d4b\u91cf\u6bcf\u4e2a\u5faa\u73af\u7528\u65f6\n\n\u5e38\u89c4\u65b9\u5f0f\n\n```python\nfrom looptick import LoopTick\nimport time\n\nlooptick = LoopTick()\n\n# \u5e38\u89c4\u8c03\u7528\u65b9\u5f0f\nfor i in range(5):\n diff = looptick.tick()\n print(f\"\u7b2c {i} \u6b21\u5faa\u73af\u8017\u65f6: {diff * looptick.NS2MS:.6f} ms\")\n time.sleep(0.01)\n \nprint(f\"\u603b\u8017\u65f6: {looptick.total_sec:.6f} \u79d2\")\nprint(f\"\u5e73\u5747\u8017\u65f6: {looptick.average_ms:.6f} ms\")\n\n# \u6216\u8005\u7528\u66f4\u7cbe\u7b80\u7684\u8bed\u6cd5\nfor i in range(5):\n diff = looptick() # \u76f4\u63a5\u8c03\u7528 __call__() \u65b9\u6cd5, \u514d\u53bb\u4e66\u5199 tick()\n print(f\"\u7b2c {i} \u6b21\u5faa\u73af\u8017\u65f6: {diff * looptick.NS2MS:.6f} ms\")\n time.sleep(0.01)\n```\n\n\u4f7f\u7528\u4e0a\u4e0b\u6587\u65b9\u5f0f\n\n```python\nfrom looptick import LoopTick\nimport time\n\nwith LoopTick() as looptick:\nwith LoopTick() as looptick:\n for i in range(5):\n diff = looptick.tick()\n print(f\"\u7b2c {i} \u6b21\u5faa\u73af\u8017\u65f6: {diff * looptick.NS2MS:.6f} ms\")\n diff = looptick.tick()\n print(f\"\u7b2c {i} \u6b21\u5faa\u73af\u8017\u65f6: {diff * looptick.NS2MS:.6f} ms\")\n time.sleep(0.01)\n```\n\n\u8f93\u51fa\u7ed3\u679c\u793a\u4f8b\uff1a\n```bash\n(LoopTick) PS C:\\IT\\LoopTick> & C:\\IT\\LoopTick\\.venv\\Scripts\\python.exe c:/IT/LoopTick/examples/with_usage.py \n\u7b2c 0 \u6b21\u5faa\u73af\u8017\u65f6: 0.000000 ms\n\u7b2c 1 \u6b21\u5faa\u73af\u8017\u65f6: 10.829900 ms\n\u7b2c 2 \u6b21\u5faa\u73af\u8017\u65f6: 16.055800 ms\n\u7b2c 3 \u6b21\u5faa\u73af\u8017\u65f6: 14.013400 ms\n\u7b2c 4 \u6b21\u5faa\u73af\u8017\u65f6: 15.587100 ms\n\u603b\u8017\u65f6: 0.056486 \u79d2\n\u5e73\u5747\u8017\u65f6: 14.121550 ms\n```\n\n\n### \u6d4b\u91cf\u884c\u95f4\u4ee3\u7801\u7528\u65f6\n```python\nfrom looptick import LoopTick\nimport time\n\ndef stage1():\n time.sleep(0.02) # \u6a21\u62df I/O \u64cd\u4f5c\n\ndef stage2():\n time.sleep(0.05) # \u6a21\u62df\u590d\u6742\u8ba1\u7b97\n\ndef stage3():\n time.sleep(0.01) # \u6a21\u62df\u8f7b\u91cf\u5904\u7406\n\n# \u4f7f\u7528\u591a\u9636\u6bb5\u6d4b\u91cf\nlinetick = LoopTick()\n\nfor i in range(3): # \u6a21\u62df 1000 \u6b21\u5faa\u73af\n\n start = linetick.tick() # \u7b2c\u4e00\u6b21\u8c03\u7528, \u8fd4\u56de\u4e00\u4e2a\u6781\u5c0f\u503c (0.000_001) \n # \u5b8c\u6210\u4e00\u6b21\u5faa\u73af\u540e, \u8fd4\u56de\u4e0a\u4e00\u6b21\u5faa\u73af\u7684 mid2 -> start \u7684\u7528\u65f6\n # \u4e00\u822c\u6211\u4eec\u4e0d\u5173\u5fc3 start \u53d8\u91cf\u7684\u503c, \u4ec5\u8868\u793a\u6d4b\u91cf\u5f00\u59cb\n stage1() \n stage2() \n\n mid1 = linetick.tick() # \u8fd4\u56de start \u2014> mid1 \u7684\u7528\u65f6\n\n stage3() \n\n mid2 = linetick.tick() # \u8fd4\u56de mid1 \u2014> mid2 \u7684\u7528\u65f6\n\n print(f\"\\n\u7b2c {i} \u6b21\u5faa\u73af\")\n print(f\"stage1() + stage2() \u8017\u65f6: {mid1 * linetick.NS2MS:.2f} ms\")\n print(f\"stage3() \u8017\u65f6: {mid2 * linetick.NS2MS:.2f} ms\")\n print(f\"\u672c\u5faa\u73af\u603b\u8017\u65f6: {(mid1 + mid2) * linetick.NS2MS:.2f} ms\")\n \nprint(f\"\\n\u5faa\u73af\u4efb\u52a1\u603b\u8017\u65f6: {linetick.total_sec:.6f} \u79d2\")\n```\n\u8f93\u51fa\u7ed3\u679c\u793a\u4f8b\uff1a\n```bash\n(LoopTick) PS C:\\IT\\LoopTick> & C:\\IT\\LoopTick\\.venv\\Scripts\\python.exe c:/IT/LoopTick/examples/lines_usage.py \n\n\u7b2c 0 \u6b21\u5faa\u73af\nstage1() + stage2() \u8017\u65f6: 93.78 ms\nstage3() \u8017\u65f6: 15.10 ms\n\u672c\u5faa\u73af\u603b\u8017\u65f6: 108.88 ms\n\n\u7b2c 1 \u6b21\u5faa\u73af\nstage1() + stage2() \u8017\u65f6: 89.86 ms\nstage3() \u8017\u65f6: 15.11 ms\n\u672c\u5faa\u73af\u603b\u8017\u65f6: 104.97 ms\n\n\u7b2c 2 \u6b21\u5faa\u73af\nstage1() + stage2() \u8017\u65f6: 89.71 ms\nstage3() \u8017\u65f6: 15.01 ms\n\u672c\u5faa\u73af\u603b\u8017\u65f6: 104.72 ms\n\n\u5faa\u73af\u4efb\u52a1\u603b\u8017\u65f6: 0.319596 \u79d2\n```\n\n### \u8fdb\u9636\u7528\u6cd5: \u591a Tick \u6d4b\u91cf\n```python\nfrom looptick import LoopTick\nimport time\n\ndef stage1():\n time.sleep(0.02) # \u6a21\u62df I/O \u64cd\u4f5c\n\ndef stage2():\n time.sleep(0.05) # \u6a21\u62df\u590d\u6742\u8ba1\u7b97\n\ndef stage3():\n time.sleep(0.03) # \u6a21\u62df\u8f7b\u91cf\u5904\u7406\n\n# \u4f7f\u7528\u591a\u9636\u6bb5\u6d4b\u91cf + \u5355\u72ec\u5faa\u73af\u6d4b\u91cf\nlinetick = LoopTick()\nlooptick = LoopTick()\n\nfor i in range(3): # \u6a21\u62df 1000 \u6b21\u5faa\u73af\n\n loop_ns = looptick.tick() # \u5355\u72ec\u4f7f\u7528\u4e00\u4e2a\u5bf9\u8c61\u6d4b\u91cf\u5faa\u73af\u65f6\u95f4\n\n start = linetick.tick() # \u7b2c\u4e00\u6b21\u8c03\u7528, \u8fd4\u56de\u4e00\u4e2a\u6781\u5c0f\u503c (0.000_001) \n # \u5b8c\u6210\u4e00\u6b21\u5faa\u73af\u540e, \u8fd4\u56de\u4e0a\u4e00\u6b21\u5faa\u73af\u7684 mid2 -> start \u7684\u7528\u65f6\n # \u4e00\u822c\u6211\u4eec\u4e0d\u5173\u5fc3 start \u53d8\u91cf\u7684\u503c, \u4ec5\u8868\u793a\u6d4b\u91cf\u5f00\u59cb\n \n stage1() \n stage2() \n\n mid1 = linetick.tick() # \u8fd4\u56de start \u2014> mid1 \u7684\u7528\u65f6\n\n stage3() \n\n mid2 = linetick.tick() # \u8fd4\u56de mid1 \u2014> mid2 \u7684\u7528\u65f6\n\n print(f\"\\n\u7b2c {i} \u6b21\u5faa\u73af\")\n print(f\"stage1() + stage2() \u8017\u65f6: {mid1 * linetick.NS2MS:.2f} ms\")\n print(f\"stage3() \u8017\u65f6: {mid2 * linetick.NS2MS:.2f} ms\")\n\n print(f\"linetick \u5bf9\u8c61\u6d4b\u91cf\u7684\u5faa\u73af\u8017\u65f6: {(mid1 + mid2) * linetick.NS2MS:.2f} ms\")\n print(f\"looptick \u5bf9\u8c61\u6d4b\u91cf\u7684\u5faa\u73af\u8017\u65f6: {loop_ns * linetick.NS2MS:.2f} ms\")\n\n \nprint(f\"\\nlinetick \u5bf9\u8c61\u6d4b\u91cf\u7684\u5faa\u73af\u4efb\u52a1\u603b\u8017\u65f6: {linetick.total_sec:.6f} \u79d2\")\n\nprint(f\"looptick \u5bf9\u8c61\u6d4b\u91cf\u7684\u5faa\u73af\u4efb\u52a1\u603b\u8017\u65f6: {looptick.total_sec:.6f} \u79d2\") \nprint(f\"looptick \u6d4b\u91cf\u7684\u6bcf\u6b21\u5faa\u73af\u5e73\u5747\u8017\u65f6: {looptick.average_ms:.6f} ms\")\n\n# \u6ce8\u610f: looptick \u5bf9\u8c61\u4f1a\u5c11\u4e00\u6b21\u5faa\u73af\u7684\u8ba1\u65f6, \u56e0\u4e3a\u5728\u7b2c\u4e00\u6b21\u8c03\u7528\u65f6\u53ea\u80fd\u8fd4\u56de\u4e00\u4e2a\u6781\u5c0f\u503c (0.000_001) \n```\n\n\u8f93\u51fa\u7ed3\u679c\u793a\u4f8b\uff1a\n```bash\n(LoopTick) PS C:\\IT\\LoopTick> & C:\\IT\\LoopTick\\.venv\\Scripts\\python.exe c:/IT/LoopTick/examples/multi_tick_usage.py\n\n\u7b2c 0 \u6b21\u5faa\u73af\nstage1() + stage2() \u8017\u65f6: 94.48 ms\nstage3() \u8017\u65f6: 45.04 ms\nlinetick \u5bf9\u8c61\u6d4b\u91cf\u7684\u5faa\u73af\u8017\u65f6: 139.52 ms\nlooptick \u5bf9\u8c61\u6d4b\u91cf\u7684\u5faa\u73af\u8017\u65f6: 0.00 ms\n\n\u7b2c 1 \u6b21\u5faa\u73af\nstage1() + stage2() \u8017\u65f6: 89.68 ms\nstage3() \u8017\u65f6: 44.96 ms\nlinetick \u5bf9\u8c61\u6d4b\u91cf\u7684\u5faa\u73af\u8017\u65f6: 134.65 ms\nlooptick \u5bf9\u8c61\u6d4b\u91cf\u7684\u5faa\u73af\u8017\u65f6: 140.12 ms\n\n\u7b2c 2 \u6b21\u5faa\u73af\nstage1() + stage2() \u8017\u65f6: 89.43 ms\nstage3() \u8017\u65f6: 44.88 ms\nlinetick \u5bf9\u8c61\u6d4b\u91cf\u7684\u5faa\u73af\u8017\u65f6: 134.31 ms\nlooptick \u5bf9\u8c61\u6d4b\u91cf\u7684\u5faa\u73af\u8017\u65f6: 135.23 ms\n\nlinetick \u5bf9\u8c61\u6d4b\u91cf\u7684\u5faa\u73af\u4efb\u52a1\u603b\u8017\u65f6: 0.409659 \u79d2\nlooptick \u5bf9\u8c61\u6d4b\u91cf\u7684\u5faa\u73af\u4efb\u52a1\u603b\u8017\u65f6: 0.275349 \u79d2\nlooptick \u6d4b\u91cf\u7684\u6bcf\u6b21\u5faa\u73af\u5e73\u5747\u8017\u65f6: 137.674650 ms\n```\n\n## \u5df2\u77e5\u95ee\u9898\n- [] \u5728\u7b2c\u4e00\u6b21\u8c03\u7528\u65f6\u53ea\u80fd\u8fd4\u56de\u4e00\u4e2a\u6781\u5c0f\u503c (0.000_001)",
"bugtrack_url": null,
"license": null,
"summary": "A simple loop execution time measurement tool.",
"version": "0.1.1",
"project_urls": {
"Source": "https://github.com/DBinK/LoopTick"
},
"split_keywords": [
"benchmark",
" loop",
" performance",
" profiling",
" timer"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "54ddff02f0729c549bf0c51d8df3a4d0a881b68c634559848bcf94b5b50f58d7",
"md5": "4ac8260a63f97721fe9ad3939040aaa3",
"sha256": "d7f15701bacdaafa27363a8c346bd7bc5ee0b30556ee67853f3a098365b9ff1f"
},
"downloads": -1,
"filename": "looptick-0.1.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "4ac8260a63f97721fe9ad3939040aaa3",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10",
"size": 4594,
"upload_time": "2025-08-12T03:57:59",
"upload_time_iso_8601": "2025-08-12T03:57:59.501732Z",
"url": "https://files.pythonhosted.org/packages/54/dd/ff02f0729c549bf0c51d8df3a4d0a881b68c634559848bcf94b5b50f58d7/looptick-0.1.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "8d71682cd0c190d7020ba50cb97a10b67d101728702e4eda16f8dff132eb430c",
"md5": "78e1a153325efe4bc67819c2e8cebafd",
"sha256": "b765259186af7b507b612b6b15b1ec675470e3a7b9593064335e3393cc4a32fc"
},
"downloads": -1,
"filename": "looptick-0.1.1.tar.gz",
"has_sig": false,
"md5_digest": "78e1a153325efe4bc67819c2e8cebafd",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 6900,
"upload_time": "2025-08-12T03:58:00",
"upload_time_iso_8601": "2025-08-12T03:58:00.594575Z",
"url": "https://files.pythonhosted.org/packages/8d/71/682cd0c190d7020ba50cb97a10b67d101728702e4eda16f8dff132eb430c/looptick-0.1.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-12 03:58:00",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "DBinK",
"github_project": "LoopTick",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "looptick"
}