Python執行緒中定位與銷毀的詳細介紹(附範例)
這篇文章帶給大家的內容是關於Python線程中定位與銷毀的詳細介紹(附示例),有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。
開工前我就覺得有什麼不太對勁,感覺要背鍋。這可不,上班第三天就捅鍋了。
我們有個了不起的後台程序,可以動態載入模組,並以執行緒方式運行,透過這種形式實現外掛程式的功能。而模組更新時候,後台程式本身不會退出,只會將模組對應的執行緒關閉、更新程式碼再啟動,6 得不行。
於是乎我就寫了個模組準備大展身手,結果忘記寫退出函數了,導致每次更新模組都新創建一個線程,除非重啟那個程序,否則那些線程就一直苟活著。
這可不行啊,得想個辦法清理呀,要不然怕是要炸了。
那麼怎麼清理呢?我能想到的就是兩步走:
找出需要清理的線程號tid;
銷毀它們;
找出線程ID
和平時的故障排查相似,先透過ps 指令看看目標行程的執行緒情況,因為已經是setName 設定過執行緒名,所以正常來說應該是看到對應的線程的。直接用下面程式碼來模擬這個執行緒:
Python 版本的多執行緒
#coding: utf8 import threading import os import time def tt(): info = threading.currentThread() while True: print 'pid: ', os.getpid() print info.name, info.ident time.sleep(3) t1 = threading.Thread(target=tt) t1.setName('OOOOOPPPPP') t1.setDaemon(True) t1.start() t2 = threading.Thread(target=tt) t2.setName('EEEEEEEEE') t2.setDaemon(True) t2.start() t1.join() t2.join()
#輸出:
root@10-46-33-56:~# python t.py pid: 5613 OOOOOPPPPP 139693508122368 pid: 5613 EEEEEEEEE 139693497632512 ...
可以看到在Python 裡面輸出的執行緒名稱就是我們設定的那樣,然而Ps 的結果卻是令我懷疑人生:
root@10-46-33-56:~# ps -Tp 5613 PID SPID TTY TIME CMD 5613 5613 pts/2 00:00:00 python 5613 5614 pts/2 00:00:00 python 5613 5615 pts/2 00:00:00 python
正常來說不該是這樣呀,我有點迷了,難道我一直都是記錯了?用別的語言版本的多執行緒來測試下:
C 版本的多執行緒
#include<stdio.h> #include<sys> #include<sys> #include<pthread.h> void *test(void *name) { pid_t pid, tid; pid = getpid(); tid = syscall(__NR_gettid); char *tname = (char *)name; // 设置线程名字 prctl(PR_SET_NAME, tname); while(1) { printf("pid: %d, thread_id: %u, t_name: %s\n", pid, tid, tname); sleep(3); } } int main() { pthread_t t1, t2; void *ret; pthread_create(&t1, NULL, test, (void *)"Love_test_1"); pthread_create(&t2, NULL, test, (void *)"Love_test_2"); pthread_join(t1, &ret); pthread_join(t2, &ret); }</pthread.h></sys></sys></stdio.h>
輸出:
root@10-46-33-56:~# gcc t.c -lpthread && ./a.out pid: 5575, thread_id: 5577, t_name: Love_test_2 pid: 5575, thread_id: 5576, t_name: Love_test_1 pid: 5575, thread_id: 5577, t_name: Love_test_2 pid: 5575, thread_id: 5576, t_name: Love_test_1 ...
用PS 指令再次驗證:
root@10-46-33-56:~# ps -Tp 5575 PID SPID TTY TIME CMD 5575 5575 pts/2 00:00:00 a.out 5575 5576 pts/2 00:00:00 Love_test_1 5575 5577 pts/2 00:00:00 Love_test_2
這個才是正確嘛,線程名確實是可以透過Ps 看出來的嘛!
不過為啥 Python 那個看不到呢?既然是透過setName
設定線程名的,那就看看定義咯:
[threading.py] class Thread(_Verbose): ... @property def name(self): """A string used for identification purposes only. It has no semantics. Multiple threads may be given the same name. The initial name is set by the constructor. """ assert self.__initialized, "Thread.__init__() not called" return self.__name @name.setter def name(self, name): assert self.__initialized, "Thread.__init__() not called" self.__name = str(name) def setName(self, name): self.name = name ...
看到這裡其實只是在Thread
物件的屬性設定了而已,並沒有動到根本,那肯定就是看不到咯~
這樣看起來,我們已經沒辦法透過ps
或/proc/
這類手段在外部搜尋python 線程名了,所以我們只能在Python 內部來解決。
於是問題就變成了,怎麼能在 Python 內部拿到所有正在執行的執行緒呢?
threading.enumerate
可以完美解決這個問題! Why?
Because 在下面這個函數的 doc 裡面說得很清楚了,傳回所有活躍的執行緒物件,不包括終止和未啟動的。
[threading.py] def enumerate(): """Return a list of all Thread objects currently alive. The list includes daemonic threads, dummy thread objects created by current_thread(), and the main thread. It excludes terminated threads and threads that have not yet been started. """ with _active_limbo_lock: return _active.values() + _limbo.values()
因為拿到的是 Thread 的對象,所以我們透過這個能到該線程相關的資訊!
請看完整程式碼範例:
#coding: utf8 import threading import os import time def get_thread(): pid = os.getpid() while True: ts = threading.enumerate() print '------- Running threads On Pid: %d -------' % pid for t in ts: print t.name, t.ident print time.sleep(1) def tt(): info = threading.currentThread() pid = os.getpid() while True: print 'pid: {}, tid: {}, tname: {}'.format(pid, info.name, info.ident) time.sleep(3) return t1 = threading.Thread(target=tt) t1.setName('Thread-test1') t1.setDaemon(True) t1.start() t2 = threading.Thread(target=tt) t2.setName('Thread-test2') t2.setDaemon(True) t2.start() t3 = threading.Thread(target=get_thread) t3.setName('Checker') t3.setDaemon(True) t3.start() t1.join() t2.join() t3.join()
輸出:
root@10-46-33-56:~# python t_show.py pid: 6258, tid: Thread-test1, tname: 139907597162240 pid: 6258, tid: Thread-test2, tname: 139907586672384 ------- Running threads On Pid: 6258 ------- MainThread 139907616806656 Thread-test1 139907597162240 Checker 139907576182528 Thread-test2 139907586672384 ------- Running threads On Pid: 6258 ------- MainThread 139907616806656 Thread-test1 139907597162240 Checker 139907576182528 Thread-test2 139907586672384 ------- Running threads On Pid: 6258 ------- MainThread 139907616806656 Thread-test1 139907597162240 Checker 139907576182528 Thread-test2 139907586672384 ------- Running threads On Pid: 6258 ------- MainThread 139907616806656 Checker 139907576182528 ...
程式碼看起來有點長,但是邏輯相當簡單,Thread-test1
和Thread-test2
都是印出目前的pid、執行緒id 和執行緒名字,然後3s 後退出,這個是想模擬執行緒正常退出。
而 Checker
執行緒則是每秒透過 threading.enumerate
輸出目前行程內所有活躍的執行緒。
可以明顯看到一開始是可以看到Thread-test1
和Thread-test2
的訊息,當它兩個退出之後就只剩下 MainThread
和Checker
本身而已了。
銷毀指定執行緒
既然能拿到名字和執行緒 id,那我們也就能幹掉指定的執行緒了!
假設現在Thread-test2
已經黑化,發瘋了,我們需要阻止它,那我們就可以透過這種方式解決了:
在上面的程式碼基礎上,增加和補上下列程式碼:
def _async_raise(tid, exctype): """raises the exception, performs cleanup if needed""" tid = ctypes.c_long(tid) if not inspect.isclass(exctype): exctype = type(exctype) res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype)) if res == 0: raise ValueError("invalid thread id") elif res != 1: ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None) raise SystemError("PyThreadState_SetAsyncExc failed") def stop_thread(thread): _async_raise(thread.ident, SystemExit) def get_thread(): pid = os.getpid() while True: ts = threading.enumerate() print '------- Running threads On Pid: %d -------' % pid for t in ts: print t.name, t.ident, t.is_alive() if t.name == 'Thread-test2': print 'I am go dying! Please take care of yourself and drink more hot water!' stop_thread(t) print time.sleep(1)
輸出
root@10-46-33-56:~# python t_show.py pid: 6362, tid: 139901682108160, tname: Thread-test1 pid: 6362, tid: 139901671618304, tname: Thread-test2 ------- Running threads On Pid: 6362 ------- MainThread 139901706389248 True Thread-test1 139901682108160 True Checker 139901661128448 True Thread-test2 139901671618304 True Thread-test2: I am go dying. Please take care of yourself and drink more hot water! ------- Running threads On Pid: 6362 ------- MainThread 139901706389248 True Thread-test1 139901682108160 True Checker 139901661128448 True Thread-test2 139901671618304 True Thread-test2: I am go dying. Please take care of yourself and drink more hot water! pid: 6362, tid: 139901682108160, tname: Thread-test1 ------- Running threads On Pid: 6362 ------- MainThread 139901706389248 True Thread-test1 139901682108160 True Checker 139901661128448 True // Thread-test2 已经不在了
一餐操作下來,雖然我們這樣對待Thread-test2
,但它還是關心著我們:多喝熱水,
PS: 熱水雖好,八杯足矣,請勿貪杯哦。
書回正傳,上述的方法是極為粗暴的,為什麼這麼說呢?
因為它的原理是:利用Python 內建的API,觸發指定執行緒的異常,讓其可以自動退出;
萬不得已真不要用這種方法,有一定機率觸發不可描述的問題。切記!別問我為什麼會知道...
為什麼停止執行緒這麼難
多執行緒本身設計就是在進程下的協作並發,是調度的最小單元,執行緒間分食著進程的資源,所以會有許多鎖定機制和狀態控制。
如果使用強製手段幹掉線程,那麼很大幾率就會出現意想不到的bug。 而且最重要的鎖定資源釋放可能也會出現意想不到問題。
我們甚至無法透過訊號殺死進程那樣直接殺線程,因為 kill 只有對付程序才能達到我們的預期,而對付線程明顯不可以,不管殺哪個線程,整個行程都會退出!
而因為有 GIL,使得許多童鞋都覺得 Python 的線程是Python 自行實現出來的,並非實際存在,Python 應該可以直接銷毀吧?
然而事實上 Python 的線程都是貨真價實的線程!
什麼意思呢? Python 的執行緒是作業系統透過 pthread 建立的原生執行緒。 Python 只是透過 GIL 來約束這些線程,來決定什麼時候開始調度,比方說運行了多少個指令就交出 GIL,至於誰奪得花魁,得聽操作系統的。
如果是單純的線程,其實係統是有辦法終止的,例如: pthread_exit
,pthread_kill
或pthread_cancel
, 詳情可看: https://www.cnblogs.com/Creat...
可惜的是: Python 層面並沒有這些方法的封裝!我的天,好氣!可能人家覺得,線程就該溫柔對待吧。
如何溫柔退出線程
想要溫柔退出線程,其實差不多就是一句廢話了~
要么運行完退出,要么設置標誌位,時常檢查標記位,該退出的就退出咯。
擴充功能
《如何正確的終止正在運行的子執行緒》:https://www.cnblogs.com/Creat...
《不要粗暴的銷毀python執行緒》 :http://xiaorui.cc/2017/02/22/...
#歡迎各位大神指點交流, QQ討論群: 258498217
轉載請註明來源: https://segmentfault.com/a/11...
##
- # Python:執行緒之定位與銷毀
8#
##
#
#
#
#
#
背景
我們有個了不起的後台程序,可以動態載入模組,並以執行緒方式運行,透過這種形式實現外掛程式的功能。而模組更新時候,後台程式本身不會退出,只會將模組對應的執行緒關閉、更新程式碼再啟動,6 得不行。
於是乎我就寫了個模組準備大展身手,結果忘記寫退出函數了,導致每次更新模組都新創建一個線程,除非重啟那個程序,否則那些線程就一直苟活著。 這可不行啊,得想個辦法清理呀,要不然怕是要炸了。 那麼怎麼清理呢?我能想到的就是兩步走:找出需要清理的線程號tid;
找出線程ID
Python 版本的多執行緒
#coding: utf8 import threading import os import time def tt(): info = threading.currentThread() while True: print 'pid: ', os.getpid() print info.name, info.ident time.sleep(3) t1 = threading.Thread(target=tt) t1.setName('OOOOOPPPPP') t1.setDaemon(True) t1.start() t2 = threading.Thread(target=tt) t2.setName('EEEEEEEEE') t2.setDaemon(True) t2.start() t1.join() t2.join()
#輸出:
root@10-46-33-56:~# python t.py pid: 5613 OOOOOPPPPP 139693508122368 pid: 5613 EEEEEEEEE 139693497632512 ...
可以看到在Python 裡面輸出的執行緒名稱就是我們設定的那樣,然而Ps 的結果卻是令我懷疑人生:
root@10-46-33-56:~# ps -Tp 5613 PID SPID TTY TIME CMD 5613 5613 pts/2 00:00:00 python 5613 5614 pts/2 00:00:00 python 5613 5615 pts/2 00:00:00 python
正常來說不該是這樣呀,我有點迷了,難道我一直都是記錯了?用別的語言版本的多執行緒來測試下:
C 版本的多執行緒#include<stdio.h>
#include<sys>
#include<sys>
#include<pthread.h>
void *test(void *name)
{
pid_t pid, tid;
pid = getpid();
tid = syscall(__NR_gettid);
char *tname = (char *)name;
// 设置线程名字
prctl(PR_SET_NAME, tname);
while(1)
{
printf("pid: %d, thread_id: %u, t_name: %s\n", pid, tid, tname);
sleep(3);
}
}
int main()
{
pthread_t t1, t2;
void *ret;
pthread_create(&t1, NULL, test, (void *)"Love_test_1");
pthread_create(&t2, NULL, test, (void *)"Love_test_2");
pthread_join(t1, &ret);
pthread_join(t2, &ret);
}</pthread.h></sys></sys></stdio.h>
登入後複製登入後複製
輸出:
#include<stdio.h> #include<sys> #include<sys> #include<pthread.h> void *test(void *name) { pid_t pid, tid; pid = getpid(); tid = syscall(__NR_gettid); char *tname = (char *)name; // 设置线程名字 prctl(PR_SET_NAME, tname); while(1) { printf("pid: %d, thread_id: %u, t_name: %s\n", pid, tid, tname); sleep(3); } } int main() { pthread_t t1, t2; void *ret; pthread_create(&t1, NULL, test, (void *)"Love_test_1"); pthread_create(&t2, NULL, test, (void *)"Love_test_2"); pthread_join(t1, &ret); pthread_join(t2, &ret); }</pthread.h></sys></sys></stdio.h>
root@10-46-33-56:~# gcc t.c -lpthread && ./a.out pid: 5575, thread_id: 5577, t_name: Love_test_2 pid: 5575, thread_id: 5576, t_name: Love_test_1 pid: 5575, thread_id: 5577, t_name: Love_test_2 pid: 5575, thread_id: 5576, t_name: Love_test_1 ...
root@10-46-33-56:~# ps -Tp 5575 PID SPID TTY TIME CMD 5575 5575 pts/2 00:00:00 a.out 5575 5576 pts/2 00:00:00 Love_test_1 5575 5577 pts/2 00:00:00 Love_test_2
這個才是正確嘛,線程名確實是可以透過Ps 看出來的嘛!
不過為啥 Python 那個看不到呢?既然是透過setName
設定線程名的,那就看看定義咯:[threading.py] class Thread(_Verbose): ... @property def name(self): """A string used for identification purposes only. It has no semantics. Multiple threads may be given the same name. The initial name is set by the constructor. """ assert self.__initialized, "Thread.__init__() not called" return self.__name @name.setter def name(self, name): assert self.__initialized, "Thread.__init__() not called" self.__name = str(name) def setName(self, name): self.name = name ...
Thread 物件的屬性設定了而已,並沒有動到根本,那肯定就是看不到咯~
這樣看起來,我們已經沒辦法透過ps
/proc/
這類手段在外部搜尋python 線程名了,所以我們只能在Python 內部來解決。 ######於是問題就變成了,怎麼能在 Python 內部拿到所有正在執行的執行緒呢? #########threading.enumerate### 可以完美解決這個問題! Why?######Because 在下面這個函數的 doc 裡面說得很清楚了,傳回所有活躍的###執行緒物件###,不包括終止和未啟動的。 ###[threading.py] def enumerate(): """Return a list of all Thread objects currently alive. The list includes daemonic threads, dummy thread objects created by current_thread(), and the main thread. It excludes terminated threads and threads that have not yet been started. """ with _active_limbo_lock: return _active.values() + _limbo.values()
#coding: utf8 import threading import os import time def get_thread(): pid = os.getpid() while True: ts = threading.enumerate() print '------- Running threads On Pid: %d -------' % pid for t in ts: print t.name, t.ident print time.sleep(1) def tt(): info = threading.currentThread() pid = os.getpid() while True: print 'pid: {}, tid: {}, tname: {}'.format(pid, info.name, info.ident) time.sleep(3) return t1 = threading.Thread(target=tt) t1.setName('Thread-test1') t1.setDaemon(True) t1.start() t2 = threading.Thread(target=tt) t2.setName('Thread-test2') t2.setDaemon(True) t2.start() t3 = threading.Thread(target=get_thread) t3.setName('Checker') t3.setDaemon(True) t3.start() t1.join() t2.join() t3.join()
root@10-46-33-56:~# python t_show.py pid: 6258, tid: Thread-test1, tname: 139907597162240 pid: 6258, tid: Thread-test2, tname: 139907586672384 ------- Running threads On Pid: 6258 ------- MainThread 139907616806656 Thread-test1 139907597162240 Checker 139907576182528 Thread-test2 139907586672384 ------- Running threads On Pid: 6258 ------- MainThread 139907616806656 Thread-test1 139907597162240 Checker 139907576182528 Thread-test2 139907586672384 ------- Running threads On Pid: 6258 ------- MainThread 139907616806656 Thread-test1 139907597162240 Checker 139907576182528 Thread-test2 139907586672384 ------- Running threads On Pid: 6258 ------- MainThread 139907616806656 Checker 139907576182528 ...
def _async_raise(tid, exctype): """raises the exception, performs cleanup if needed""" tid = ctypes.c_long(tid) if not inspect.isclass(exctype): exctype = type(exctype) res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype)) if res == 0: raise ValueError("invalid thread id") elif res != 1: ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None) raise SystemError("PyThreadState_SetAsyncExc failed") def stop_thread(thread): _async_raise(thread.ident, SystemExit) def get_thread(): pid = os.getpid() while True: ts = threading.enumerate() print '------- Running threads On Pid: %d -------' % pid for t in ts: print t.name, t.ident, t.is_alive() if t.name == 'Thread-test2': print 'I am go dying! Please take care of yourself and drink more hot water!' stop_thread(t) print time.sleep(1)
root@10-46-33-56:~# python t_show.py pid: 6362, tid: 139901682108160, tname: Thread-test1 pid: 6362, tid: 139901671618304, tname: Thread-test2 ------- Running threads On Pid: 6362 ------- MainThread 139901706389248 True Thread-test1 139901682108160 True Checker 139901661128448 True Thread-test2 139901671618304 True Thread-test2: I am go dying. Please take care of yourself and drink more hot water! ------- Running threads On Pid: 6362 ------- MainThread 139901706389248 True Thread-test1 139901682108160 True Checker 139901661128448 True Thread-test2 139901671618304 True Thread-test2: I am go dying. Please take care of yourself and drink more hot water! pid: 6362, tid: 139901682108160, tname: Thread-test1 ------- Running threads On Pid: 6362 ------- MainThread 139901706389248 True Thread-test1 139901682108160 True Checker 139901661128448 True // Thread-test2 已经不在了
書回正傳,上述的方法是極為粗暴的,為什麼這麼說呢?
因為它的原理是:利用Python 內建的API,觸發指定執行緒的異常,讓其可以自動退出;
萬不得已真不要用這種方法,有一定機率觸發不可描述的問題。切記!別問我為什麼會知道...
為什麼停止執行緒這麼難
多執行緒本身設計就是在進程下的協作並發,是調度的最小單元,執行緒間分食著進程的資源,所以會有許多鎖定機制和狀態控制。
如果使用強製手段幹掉線程,那麼很大幾率就會出現意想不到的bug。 而且最重要的鎖定資源釋放可能也會出現意想不到問題。
我們甚至無法透過訊號殺死進程那樣直接殺線程,因為 kill 只有對付程序才能達到我們的預期,而對付線程明顯不可以,不管殺哪個線程,整個進程都會退出!
而因為有 GIL,使得許多童鞋都覺得 Python 的線程是Python 自行實現出來的,並非實際存在,Python 應該可以直接銷毀吧?
然而事實上 Python 的線程都是貨真價實的線程!
什麼意思呢? Python 的執行緒是作業系統透過 pthread 建立的原生執行緒。 Python 只是透過 GIL 來約束這些線程,來決定什麼時候開始調度,比方說運行了多少個指令就交出 GIL,至於誰奪得花魁,得聽操作系統的。
如果是單純的線程,其實係統是有辦法終止的,例如: pthread_exit
,pthread_kill
或pthread_cancel
, 詳情可看: https://www.cnblogs.com/Creat...
可惜的是: Python 層面並沒有這些方法的封裝!我的天,好氣!可能人家覺得,線程就該溫柔對待吧。
如何溫柔退出線程
想要溫柔退出線程,其實差不多就是一句廢話了~
要么運行完退出,要么設置標誌位,時常檢查標記位,該退出的就退出咯。
擴充
《如何正確的終止正在運行的子執行緒》:https://www.cnblogs.com/Creat...
《不要粗暴的銷毀python執行緒》 :http://xiaorui.cc/2017/02/22/...
#歡迎各位大神指點交流, QQ討論群: 258498217
轉載請註明來源: https://segmentfault.com/a/11...
#保留所有權利
如果你覺得我的文章對你有用,請隨意讚賞
你可能感興趣的
2 評論
時間排序
############################################################################################################################## ######################水平)) ###### #### ‧ 1 天前### ################若是我可能kill -9了,寧可錯殺一千,不可放過一個,蛤蛤###
# 讚 # #
##啊~ -9 流程裡一樣全死了~##########啊~#########># ##1
‧ 1 天前中上載入中...
以上是Python執行緒中定位與銷毀的詳細介紹(附範例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

PHP主要是過程式編程,但也支持面向對象編程(OOP);Python支持多種範式,包括OOP、函數式和過程式編程。 PHP適合web開發,Python適用於多種應用,如數據分析和機器學習。

PHP適合網頁開發和快速原型開發,Python適用於數據科學和機器學習。 1.PHP用於動態網頁開發,語法簡單,適合快速開發。 2.Python語法簡潔,適用於多領域,庫生態系統強大。

Linux系統的五個基本組件是:1.內核,2.系統庫,3.系統實用程序,4.圖形用戶界面,5.應用程序。內核管理硬件資源,系統庫提供預編譯函數,系統實用程序用於系統管理,GUI提供可視化交互,應用程序利用這些組件實現功能。

PHP起源於1994年,由RasmusLerdorf開發,最初用於跟踪網站訪問者,逐漸演變為服務器端腳本語言,廣泛應用於網頁開發。 Python由GuidovanRossum於1980年代末開發,1991年首次發布,強調代碼可讀性和簡潔性,適用於科學計算、數據分析等領域。

Golang在性能和可擴展性方面優於Python。 1)Golang的編譯型特性和高效並發模型使其在高並發場景下表現出色。 2)Python作為解釋型語言,執行速度較慢,但通過工具如Cython可優化性能。

Python更易學且易用,C 則更強大但複雜。 1.Python語法簡潔,適合初學者,動態類型和自動內存管理使其易用,但可能導致運行時錯誤。 2.C 提供低級控制和高級特性,適合高性能應用,但學習門檻高,需手動管理內存和類型安全。

要安裝 Laravel,需依序進行以下步驟:安裝 Composer(適用於 macOS/Linux 和 Windows)安裝 Laravel 安裝器創建新項目啟動服務訪問應用程序(網址:http://127.0.0.1:8000)設置數據庫連接(如果需要)

Python在開發效率上優於C ,但C 在執行性能上更高。 1.Python的簡潔語法和豐富庫提高開發效率。 2.C 的編譯型特性和硬件控制提升執行性能。選擇時需根據項目需求權衡開發速度與執行效率。
