本篇文章將深入介紹如何在Windows上設定開發環境,以實現從Windows到aarch64的跨平台編譯。 MinGW 是一個用於 Windows 平台的開發工具套件,其目的是提供一個在 Windows 上使用類 Unix 工具(如 GCC 編譯器)的環境,以便開發者能夠輕鬆地在 Windows 上進行跨平台的程式碼開發。 以下是 MinGW 的主要特點和組成部分:
在開始之前,我們需要確保Windows上安裝了適當的交叉編譯工具鏈。這包括編譯器、連結器和其他相關工具。我們可以依照需求安裝Cygwin、MinGW或其他工具,以便支援aarch64的交叉編譯。
安裝完工具後,設定環境變數是確保系統能夠找到這些工具的關鍵步驟。在Windows環境中,這可能包括修改系統的PATH變數以包含交叉編譯工具的路徑。這確保了在命令提示字元或其他開發環境中能夠正確調用這些工具。
在這一部分,我們將進一步探討如何設定CMake和編譯程式碼的步驟,以實現從Windows到aarch64的跨平台編譯。
首先讓我們來看一下CMakeLists.txt文件的內容。這個文件是使用CMake進行專案管理的配置文件。在這裡我們設定了交叉編譯所需的參數。
# CMakeLists.txt
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_C_COMPILER "aarch64-linux-gnu-gcc-7.5.0.exe")
set(CMAKE_CXX_COMPILER "aarch64-linux-gnu-g++.exe")
project(hello_world)
add_executable(main main.cpp)
這個CMakeLists.txt
文件告訴CMake使用aarch64-linux-gnu-gcc-7.5.0.exe
和aarch64-linux-gnu-g++.exe
作為交叉編譯工具,並建立一個名為main
的可執行檔案。
接下來我們來看一下main.cpp
文件的內容。這是一個簡單的C++應用程式,只是輸出一個 “hello world” 的訊息。
// main.cpp
#include <iostream>
int main(){
std::cout << "hello word" << std::endl;
}
接著我們可以直接在編譯器(ex: VSCode)點選 Build 按鈕,VSCode 會自動偵測 CMakeLists 內容並編譯執行檔。
又或者可以輸入以下指令手動觸發 cmake。第一條指令是配置項目,CMake將根據CMakeLists.txt文件和項目的結構生成構建系統所需的文件。第二條指令是根據前一步的配置訊息,使用構建系統(make)進行實際的項目構建。
# 配置項目
cmake -S . -B build -G "MinGW Makefiles"
# 建構項目
cmake --build build
如果不想用 cmake 編譯可以直接使用 aarch64-linux-gnu-g++
編譯執行檔。
aarch64-linux-gnu-g++ -o main .\main.cpp
在 VSCode 中如果有安裝 CMake 擴充套件,可以使用快捷鍵建立一個 CMake C++ 板模。注意請在 windows 系統環境變數先配置好 mingw toolchain。
在程式開發的初期,我們經常使用簡單的 print 方法來輸出訊息和進行除錯。這是一種快速而直接的方法,但當程式上線運行時,我們需要更多進階的工具來處理各種事件和特殊狀況,例如未預期的錯誤。這些狀態的紀錄對於日後的問題追蹤和系統分析來說非常重要。在這種情況下,簡單的 print 已經無法應對了。Python 提供了一個強大的 logging 方法,允許開發者靈活地管理和紀錄程式運行時的事件。
Logging 將訊息等級分為六個等級,分別是:NOTSET、DEBUG、INFO、WARNING、ERROR、CRITICAL。每個等級都有一個對應的數值,而 logging 只會紀錄等級數值大於或等於設定值的訊息。以下是每個等級的簡要描述:
首先載入內建的 logging 庫,接下來我們可以配置 logging,並使用各種不同等級的 logging 方法來記錄訊息。
import logging
# 配置 logging,設定等級為 WARNING
logging.basicConfig(level=logging.WARNING)
# 使用不同等級的 logging 方法
logging.debug('這是一條 DEBUG 訊息')
logging.info('這是一條 INFO 訊息')
logging.warning('這是一條 WARNING 訊息')
logging.error('這是一條 ERROR 訊息')
logging.critical('這是一條 CRITICAL 訊息')
由於定義輸出等級為WARNING,因此僅有大於等於WARNING等級的 WARNING、ERROR、CRITICAL會有輸出顯示,下述為輸出結果。
WARNING:root:這是一條 WARNING 訊息
ERROR:root:這是一條 ERROR 訊息
CRITICAL:root:這是一條 CRITICAL 訊息
要使 logging 更詳細,可以添加其他相關的資訊,例如時間戳記、模組名稱、函數名稱等。這可以透過修改 logging 的格式來實現。此外之外我們也能將 log 訊息輸出成指定檔名的文字檔。須在 logging.basicConfig()
裡面的 filename 參數設定要儲存的日誌檔名,即可以將 logging 儲存起來。
import logging
import sys
import time
# 取得當下系統時間
localtime = time.localtime()
# 處理 log 的基本設定
logging.basicConfig(
level = logging.INFO,
format = '%(asctime)s - %(levelname)s : %(message)s',
filename = './dev_log_' + time.strftime( "%Y_%m", localtime ) + '.txt'
)
# 使用不同等級的 logging 方法
logging.debug('這是一條 DEBUG 訊息')
logging.info('這是一條 INFO 訊息')
logging.warning('這是一條 WARNING 訊息')
logging.error('這是一條 ERROR 訊息')
logging.critical('這是一條 CRITICAL 訊息')
實際輸出結果:
2023-12-01 21:14:07,546 - INFO : 這是一條 INFO 訊息
2023-12-01 21:14:07,546 - WARNING : 這是一條 WARNING 訊息
2023-12-01 21:14:07,546 - ERROR : 這是一條 ERROR 訊息
2023-12-01 21:14:07,546 - CRITICAL : 這是一條 CRITICAL 訊息
我們也可以記錄 Exception 的錯誤訊息。在這個範例中,我們首先配置了 logging,將等級設定為 ERROR。接著,我們使用 try 和 except 塊來包裹可能引發異常的程式碼。當異常發生時,logging.exception
方法會捕獲並記錄異常訊息,同時保留原始的異常類型和 stack trace。
import logging
# 配置 logging,設定等級為 ERROR
logging.basicConfig(
level=logging.ERROR,
format='%(asctime)s - %(levelname)s - %(funcName)s:%(lineno)d - %(message)s'
)
try:
throw_error()
except Exception as e:
logging.exception('An exception occurred: %s', str(e))
輸出結果:
2023-12-01 21:27:09,370 - ERROR - <module>:12 - An exception occurred: name 'throw_error' is not defined
Traceback (most recent call last):
File "/Users/Desktop/demo/run.py", line 10, in <module>
throw_error()
^^^^^^^^^^^
NameError: name 'throw_error' is not defined
在 Python 開發中,經常需要使用環境變數來配置應用程式的行為。而 python-dotenv 是一個簡單而強大的工具,它使得管理和載入這些環境變數變得更加輕鬆。在本文中我們將了解如何使用 python-dotenv,將環境變數的管理變得更加簡單而清晰。無論是在本地開發環境還是部署到伺服器上,python-dotenv 都能確保你的應用程式在各種情境下順暢運行。
python-dotenv 允許我們使用一個名為 .env
的文件,將所有的環境變數集中在一處。這樣我們就可以在不同的環境中輕鬆切換,而不必修改程式碼。這對於開發、測試和部署的流程是極為方便。首先輸入以下指令安裝套件:
pip install python-dotenv
VERSION = 1.0.0
from dotenv import load_dotenv
# 載入 .env 文件中的變數
load_dotenv()
import os
# 讀取 VERSION 環境變數
version = os.environ.get('VERSION')
# 輸出讀取到的值
print(f"VERSION value: {version}")
最後執行 python xxx.py 該變數自動會根據環境變數檔的設定透過 dotenv 讀取數值。
如果有使用 docker 部署 python 相關的應用的話,可以透過 docker-compose.yml
中的 environment 設定環境變數。無論是指定敏感的 API 金鑰、設定執行模式,還是定義應用程式行為的其他參數,docker-compose.yml
的 environment 設定為我們提供了一個方便、統一的管理方式。
version: '3.0'
services:
myapp:
build: .
image: myapp-dockercompose
container_name: myapp-compose-container
ports:
- 8001:8001
volumes:
- /etc/ssl:/etc/ssl
environment:
- VERSION = 1.0.0
接著
import os
# 讀取 VERSION 環境變數
version = os.environ.get('VERSION')
# 輸出讀取到的值
print(f"VERSION value: {version}")
在 Linux 中,cron 是一個用於定期執行任務的工具。這些定期執行的任務可以是腳本、命令、或者其他可以在終端中執行的操作。cron 工具的主要組件是 cron 和 crontab。
crontab -e
crontab -l
crontab -r
星號(*)表示”每”,因此 * * * * * 表示每分鐘都執行一次。你可以使用具體的數字,例如 30 1 * * * 表示每天的1:30執行。
* * * * * command_to_be_executed
- - - - -
| | | | |
| | | | +----- 執行命令的星期幾 (0 - 7) (星期天是 0 或 7)
| | | +------- 執行命令的月份 (1 - 12)
| | +--------- 執行命令的日期 (1 - 31)
| +----------- 執行命令的小時 (0 - 23)
+------------- 執行命令的分鐘 (0 - 59)
以下是一些例子:
0 0 * * * command_to_be_executed
30 9 * * 1 command_to_be_executed
*/10 * * * * command_to_be_executed
cron 還可以透過其他方式更複雜的設置,例如使用 @reboot
來在系統啟動時執行,或者使用@daily
、@weekly
等預定義的時間。cron 是一個強大的任務調度工具,能夠自動執行各種任務,提高系統的自動化和效率。
cron 是一個強大的任務調度工具,它允許使用者根據自己的需求指定定時執行的頻率。使用者只需將指令或程式的執行時間設定在 crontab 設定檔中,不必手動執行這些工作。這樣一來,系統就能夠在背後按照預定的時間表執行這些工作,使得定期性的任務得以自動化,提高了系統的效率和管理的方便性。
若要編輯自己的 crontab 內容可以直接輸入 crontab -e
進入終端畫面直接輸入執行指令。又或者是在任一資料夾建立一個 myjob(檔名任意)。然後輸入欲執行的時間與腳本。這兩行是用來設定 cron 任務的表達式。在 cron 表達式中,分別用來指定分、時、日、月、星期的時間。接著是執行帳號,表示該任務由哪個用戶執行。最後是指令,表示要執行的命令或腳本。
# 分 時 日 月 星期 執行帳號 指令...
* * * * * echo "hello" >> "/tmp/crontab.log"
*/1 * * * * sh /tmp/script.sh >/tmp/stdout.log 2>/tmp/stderr.log
記得多留一個換行。
接著輸入以下指令將寫好的排程啟動,它的作用是將 myjob 這個文件安裝為你的 cron 任務表。具體來說,myjob 文件應該包含一個或多個 cron 表達式以及相應的要執行的命令或腳本。
crontab myjob
另外記得在 /tmp
底下新增 script.sh
。這是一個 bash 腳本,這個腳本的目的是在 /tmp/hello.txt
文件中寫入包含日期時間前綴的 “hello” 訊息,同時在終端上顯示腳本啟動的時間。這樣的腳本可能被用於執行一些需要時間戳的工作,或者用於紀錄腳本的執行狀態。
#!/bin/bash
echo "Starting script $(date)"
echo "$(date): hello" >> /tmp/hello.txt
注意第一行的
Starting script $(date)
會被寫到tmp/stdout.log
第二行的
$(date): hello
會另外被寫檔到/tmp/hello.txt
在 Docker 中必續執行 CMD cron 啟動排程。也可以透過以下指令查看是否 cron 被正確運行在背景。
ps -ef | grep cron
若要停止 cron:
/etc/init.d/cron stop
範例程式碼:https://github.com/1010code/crontab-tutorial
]]>對於 SVG 圖示或圖形,如果要作為 CSS 背景使用,通常只要尺寸不超過2KB,就會直接內嵌到 CSS 程式碼中。這種方法 SVG 不需要額外的檔案請求,渲染幾乎沒有延遲,可以提高網頁的載入效能。
各位可以使用線上的網頁服務,用記事本將原始的 SVG 貼到以下連結網頁,接著就會自動地幫我們產生 data:image/svg+xml
格式的圖檔。
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' version='1.1' xmlns:xlink='http://www.w3.org/1999/xlink' width='512' height='512' x='0' y='0' viewBox='0 0 512 512' style='enable-background:new 0 0 512 512' xml:space='preserve' class=''%3E%3Cg%3E%3Cg data-name='Layer 2'%3E%3Ccircle cx='256' cy='256' r='256' fill='%23ffc107' opacity='1' data-original='%23ff2147' class=''%3E%3C/circle%3E%3Crect width='65.74' height='280' x='223.13' y='116' fill='%23ffffff' rx='18.26' transform='rotate(-90 256 256)' opacity='1' data-original='%23ffffff' class=''%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
background-repeat: no-repeat no-repeat;
background-position: center center;
background-size: cover;
通常在撰寫程式的時候需要依據不同硬體或 toolchain 產生相對應的巨集定義,如果每一次編譯程式都要手動的去修改 define 太麻煩了。因此在 CMake 中可以使用 configure_file 將一份文件(.in)從某位置複製到另一個位置,並且替代掉 CMake 的設置變數。
這裡舉一個例子。假設我想設定一個版本號的巨集定義,並透過 CMake 編譯時將版本號動態的配置在 define.h
。文件目錄結構如下:
.
├── CMakeLists.txt
├── define.h.in
└── main.cpp
我們可以在 CMakeLists.txt
中設定變數先定義好版本號。接著使用 configure_file 命令來配置一個文件。它的作用是將 define.h.in 文件中的內容複製到 define.h 文件中,並將其中的CMake變數替換為它們的實際值。@ONLY 選項表示僅替換 define.h.in 中使用@符號包圍的變數。這通常用於生成配置文件,例如本範例將版本號嵌入到程式碼中。
# CMakeLists.txt
project(Demo)
set(BUIDL_VERSION 1.1.0)
configure_file("${PROJECT_SOURCE_DIR}/define.h.in"
"${PROJECT_SOURCE_DIR}/define.h" @ONLY)
add_executable(main main.cpp)
接著在主程式中引入自動生成的定義檔 define.h
,並且把版本號印出來。
// main.cpp
#include <iostream>
#include "define.h"
int main() {
std::cout << "BUIDL_VERSION: "<< BUIDL_VERSION << std::endl;
}
以下是 configure_file 命令的主要參數:
configure_file(<input> <output>
[NO_SOURCE_PERMISSIONS | USE_SOURCE_PERMISSIONS |
FILE_PERMISSIONS <permissions>...]
[COPYONLY] [ESCAPE_QUOTES] [@ONLY]
[NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ])
使用 configure_file()
指令可以減少在 CMakeLists.txt
文件中使用 add_compile_options()
等指令的需要。只需在 CMakeLists.txt
文件中定義變數,然後在 .h.in
文件中使用@@符號進行引用即可。這樣可以更簡單地生成配置文件並將變數的值注入到程式碼中。
在 CMake 3.11 及之前的版本中,可以使用 add_definitions 來定義編譯時期巨集,但此方法較不建議使用,因為它可能會對整個專案中的所有目標產生影響,而不僅僅是特定目標。
使用方式如下:
add_definitions("-D HELLO")
在 CMake 3.12 及其之後的版本中,推薦使用 add_compile_definitions 來定義編譯時期巨集。這個指令更加直觀且符合現代的寫法。 add_compile_definitions 可以用來添加編譯時期的巨集定義,這些定義在編譯過程中會被傳遞給編譯器。
使用方式如下:
target_compile_definitions(main PUBLIC HELLO)
compile_commands.json
,這一份檔案中詳細記載了編譯資訊。主要是要讓 vs code 讀取到 define 這樣編輯器才會自動偵測並將有效的區塊程式碼高量顯示。{
"configurations": [
{
"name": "Win32",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/libs/My_library/include",
],
"configurationProvider": "ms-vscode.cpptools",
"compileCommands": "${workspaceFolder}/build/compile_commands.json",
"defines": ["HELLO"] // 也可以手動給予巨集,vs code 就會自動高量顯示
}
],
"version": 4
}
c_cpp_properties.json 由 vscode 自動生成,放置於 .vscode 資料夾下。
首先我們建立一個 main.cpp
並且使用一個條件編譯指令,用於判斷是否定義了名為 HELLO 的符號。如果這個符號已經被定義,則編譯器會執行 #ifdef 到 #endif 之間的程式碼。如果 HELLO 沒有被定義,這段程式碼將被忽略。
// main.cpp
#include <iostream>
int main()
{
#ifdef HELLO
std::cout << "!!!@@@@!!!" << std::endl;
#endif
std::cout << "Hello, world!\n";
}
接著我們可以在 CMake 文件中宣告定義巨集。這樣在編譯 main 時裡面的內容就會被編譯了。
# CMakeLists.txt
project (HELLO)
add_definitions("-D HELLO")
add_executable(main main.cpp)
執行編譯:
cmake -B build -G "MinGW Makefiles" -S .
cmake --build build
.\build\main.exe
由於我們在 CMake 定義了 HELLO,因此最後執行檔運行時將會輸出 “!!!@@@@!!!”。
在現代網絡世界中,保障用戶數據的安全性和隱私已經變得至關重要。網站的 SSL 憑證是實現這一目標的關鍵元素之一。在本文中,我們將探討如何使用 Nginx 這個廣泛應用的 Web 伺服器來為你的網站加入 SSL 憑證。
尚未安裝 Nginx 可以參考 反向代理 Nginx 伺服器架設
我們可以監聽443PORT也就是網址輸入的https就能轉址到8002PORT。實際上使用者在瀏覽器輸入 https://example.com 自動會連線到 https://127.0.0.1:8002 的 API 服務。
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /path/to/ssl_certificate.cer;
ssl_certificate_key /path/to/ssl_certificate.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_pass https://127.0.0.1:8002;
proxy_set_header Host $host;
}
}
8002 PORT 的 API 必須先掛上憑證。
假設我使用 Python 架設一個 FastAPI,可以使用 gunicorn 或是 uvicorn 來啟動。並同時加上 ssl 憑證
gunicorn -w 2 -b 0.0.0.0:8001 run:app -k uvicorn.workers.UvicornWorker -t 0 --keyfile=/etc/ssl/example.com.key --certfile=/etc/ssl/example.com.crt --daemon
uvicorn run:app --reload --host 0.0.0.0 --port 8001 --ssl-keyfile=/etc/ssl/example.com.key --ssl-certfile=/etc/ssl/example.com.crt
以下設定一個情境題。首先撰寫一個 API 並且佔用 8002 PORT。接著我們可以透過 8001 Nginx 監聽並掛上 ssl 憑證,並且透過 proxy_pass 反向代理,將請求轉發到 8002 PORT。實際上使用者在瀏覽器輸入 https://example.com:8001 自動會連線到 127.0.0.1:8002 的 API 服務。
server {
listen 8001 ssl;
server_name example.com;
ssl_certificate /path/to/ssl_certificate.cer;
ssl_certificate_key /path/to/ssl_certificate.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_pass http://127.0.0.1:8002;
proxy_set_header Host $host;
}
}
在這個設定中,Nginx 會監聽8002端口,並將請求路由到對應的服務器。這個設定的目的是將所有請求重新導向到 https://tw.yahoo.com
這個網址。
首先,listen 指令指定 Nginx 監聽的端口為8002。這意味著當用戶通過訪問這個伺服器的IP地址或域名的8002端口時,Nginx 會處理這些請求。接下來,server_name 指令定義了這個虛擬主機的名稱。在這個例子中,它指定了兩個值:”192.168.xx.xx”和”example.com”。這意味著當請求到達伺服器時,如果域名或IP地址與這些值之一匹配,Nginx 將使用這個設定來處理請求。最後,location / 塊定義了對根路徑的處理方式。在這個設定中,它使用了 return 301 指令,將所有到這個虛擬主機的請求都重定向到”https://tw.yahoo.com”。這意味著無論用戶訪問這個伺服器的哪個URL,Nginx 都會返回 301 Moved Permanently 狀態碼並將客戶端重定向到 Yahoo 首頁。
server{
listen 8002;
server_name 192.168.xx.xx example.com;
location / {
return 301 https://tw.yahoo.com;
}
}
server{
listen 8002 ssl;
ssl_certificate /etc/ssl/example.com.cer;
ssl_certificate_key /etc/ssl/example.com.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
server_name example.com;
location / {
return 301 https://tw.yahoo.com;
}
}
上述範例中 location 可以使用 proxy_pass 或 return,然而兩者使用時機不同。
此外在使用 return 時候格式如下:
本篇文章將提供四種方法,在 Python 環境中測量程式碼運行時間。
Python 內建的 time 函式庫提供非常多的時間函式可以呼叫。其中 time.time()
提供1秒的精度,若需要量測極為精細的運行時間可以採用 time.perf_counter_ns()
。該方法返回時間為納秒,用於測量較短持續時間的具有最高有效精度的時鐘。它會包括睡眠狀態所消耗的時間並且作用於全系統範圍。
#coding:utf8
import numpy as np
import time
start = time.perf_counter_ns()
a = np.arange(10000000)
a = a**2
timeuse = time.perf_counter_ns() - start
print(f'Elapsed time in nanoseconds: {timeuse} ns')
print(f'Elapsed time in microseconds: {timeuse / 1000} μs')
print(f'Elapsed time in milliseconds: {timeuse / 1000000} ms')
print(f'Elapsed time in seconds: {timeuse / 1000000000} s')
輸出結果:
Elapsed time in nanoseconds: 22091600 ns
Elapsed time in microseconds: 22091.6 μs
Elapsed time in milliseconds: 22.0916 ms
Elapsed time in seconds: 0.0220916 s
另外還可以使用 time.process_time(),主要的差異在於 time.perf_counter() 會計算 sleep() 的時間,而 time.process_time() 不會。
該方法實現於 Python 3.7 或以上
timeit 是 Python 的一個模組,可以用來測量執行某段程式碼的時間。
import timeit
import numpy as np
start_time = timeit.default_timer()
a = np.arange(10000000)
a = a**2
end_time = timeit.default_timer()
timeuse = end_time - start_time
print(f'Elapsed time in nanoseconds: {timeuse*1000000000} ns')
print(f'Elapsed time in microseconds: {timeuse*1000000} μs')
print(f'Elapsed time in milliseconds: {timeuse*1000} ms')
print(f'Elapsed time in seconds: {timeuse } s')
輸出結果:
Elapsed time in nanoseconds: 23822599.99999997 ns
Elapsed time in microseconds: 23822.599999999973 μs
Elapsed time in milliseconds: 23.822599999999973 ms
Elapsed time in seconds: 0.02382259999999997 s
需要注意的是,為了獲得更準確的結果,通常需要多次執行相同的程式碼並計算平均運行時間,可以使用 timeit 模組提供的 repeat() 方法實現這一點。
line_profiler 是 Python 的一個性能分析工具,可以用來分析 Python 程式碼的效能,查看哪些函數、行程式碼執行時間長,以及哪些函數、行程式碼被調用次數多,可以用來找出程式的瓶頸,提升程式執行效能。
首先使用指令安裝 line_profiler 庫
pip install line_profiler
編寫要測量的 Python 程式碼,並在函數上添加 @profile 裝飾器。最後將它儲存成 .py
檔。
#coding:utf8
from line_profiler import LineProfiler
import numpy as np
@profile
def call():
a = np.arange(10000000)
a = a**2
if __name__=='__main__':
call()
使用 line_profiler 庫測量 Python 程式碼的性能,使用以下命令:
kernprof -l -v my_script.py
這條命令將使用 line_profiler 測量 Python 每行程式碼的性能,並在終端顯示詳細訊息。 輸出結果:
Total time: 0.0215657 s
File: .\time_profiler_test.py
Function: call at line 22
Line # Hits Time Per Hit % Time Line Contents
==============================================================
22 @profile
23 def call():
24 1 9447.7 9447.7 43.8 a = np.arange(10000000)
25 1 12118.0 12118.0 56.2 a = a**2
在 line_profiler 的性能分析結果中,常見的列名和其意義如下:
另一個常用的性能測量方法是使用 Python 的 cProfile 模組。與 line_profiler 類似,cProfile 可以提供程式碼中每個函數的執行時間和調用次數。相比於 line_profiler,cProfile 的輸出結果更加精簡和易於閱讀。
#coding:utf8
import cProfile
import numpy as np
def call():
a = np.arange(10000000)
a = a**2
if __name__=='__main__':
# 使用 cProfile 運行函數
cProfile.run('call()')
將上述程式碼儲存成 .py
格式,並在終端機輸入以下指令:
python .\my_script.py
輸出結果:
5 function calls in 0.024 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.003 0.003 0.024 0.024 <string>:1(<module>)
1 0.012 0.012 0.021 0.021 time_profiler_test.py:35(call)
1 0.009 0.009 0.009 0.009 {built-in method numpy.arange}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
在 cProfile 的性能分析結果中,常見的列名和其意義如下:
time.perf_counter_ns()
方法是一個簡單而有效的方法,它可以快速測量整個程式的運行時間,以便與其他版本進行比較。import time
start_time = time.perf_counter()
# 在這裡執行要測量運行時間的代碼
end_time = time.perf_counter()
elapsed_time = end_time - start_time
cpu_speed = 1.2 # CPU 時脈速度,單位是 GHz
cpu_cycles = elapsed_time * cpu_speed * 1e9 # 將時間換算為 CPU cycle 數
print("運行時間(秒):", elapsed_time)
print("CPU cycle 數:", cpu_cycles)
本文將介紹如何使用 Axios 庫進行檔案上傳以及追蹤上傳進度。Axios 是一個流行的 JavaScript 庫,用於發送 HTTP 請求,它具有簡單易用的 API 和強大的功能。我們將透過範例程式碼來展示如何引入 Axios,建立包含檔案上傳功能的 HTML 表單,以及如何使用 onUploadProgress 來追蹤上傳進度。
首先需要載入 Axios 的 CDN。
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.0.0-alpha.1/axios.min.js"></script>
為了進行上傳,需要建立一個表單,其中包含一個類型為 file 的 <input>
元素,以及一個提交表單的按鈕:
<!-- 表單 -->
<form id="form">
<input type="file" accept=".png, .jpg" id="file">
<button type="submit">上傳檔案!</button>
</form>
接下來,建立進度條。這只是一個 <progress>
元素。可以使用標籤內的文字來顯示進度條的相關資訊:
<!-- 進度條 -->
<div>
<label for="progress-bar">0%</label>
<progress id="progress-bar" value="0" max="100"></progress>
</div>
在 JavaScript 中,可以透過 FormData 物件來處理表單提交內容。它首先獲取了表單元素和進度條 Dom,然後綁定了一個 submit 事件的監聽器。當使用者提交表單時,該事件觸發,並執行相應的處理程序。
const form = document.getElementById('form');
const bar = document.getElementById('progress-bar');
form.addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData();
const file = document.getElementById('file');
const img = file.files[0];
formData.append('image', img);
// 這裡添加 POST 請求
})
接著可以使用 Axios 選擇圖像作為 POST 請求發送。
這段程式碼實現了檔案上傳功能,並通過追蹤上傳進度來更新使用者介面中的進度條。在檔案上傳過程中,使用者可以清楚地看到檔案上傳的進度。
const form = document.getElementById('form');
const bar = document.getElementById('progress-bar');
form.addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData();
const file = document.getElementById('file');
const img = file.files[0];
formData.append('image', img);
// Axios
const config = {
onUploadProgress: function(progressEvent) {
const percentCompleted = Math.round((progressEvent.loaded / progressEvent.total) * 100);
bar.setAttribute('value', percentCompleted);
bar.previousElementSibling.textContent = `${percentCompleted}%`;
if (percentCompleted === 100) {
bar.previousElementSibling.textContent = `上傳完成!`;
}
}
};
axios.post('https://httpbin.org/post', formData, config)
.then(res => console.log(res))
.catch(err => console.log(err));
});