本篇文章给大家带来的内容是关于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/syscall.h> #include<sys/prctl.h> #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); }
输出:
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...
3 天前发布
Python:线程之定位与销毁
c
linux
python
266 次阅读 · 读完需要 30 分钟
8
背景
开工前我就觉得有什么不太对劲,感觉要背锅。这可不,上班第三天就捅锅了。
我们有个了不起的后台程序,可以动态加载模块,并以线程方式运行,通过这种形式实现插件的功能。而模块更新时候,后台程序自身不会退出,只会将模块对应的线程关闭、更新代码再启动,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/syscall.h> #include<sys/prctl.h> #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); }
输出:
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...
保留所有权利
如果觉得我的文章对你有用,请随意赞赏
你可能感兴趣的
2 条评论
舞林 · 1 天前
如果是我可能kill -9了,宁可错杀一千,不可放过一个,蛤蛤
赞
不行呀~ -9 进程里全死了~
Atas ialah kandungan terperinci Python线程中定位与销毁的详细介绍(附示例). Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Python dan C masing -masing mempunyai kelebihan sendiri, dan pilihannya harus berdasarkan keperluan projek. 1) Python sesuai untuk pembangunan pesat dan pemprosesan data kerana sintaks ringkas dan menaip dinamik. 2) C sesuai untuk prestasi tinggi dan pengaturcaraan sistem kerana menaip statik dan pengurusan memori manual.

Memilih Python atau C bergantung kepada keperluan projek: 1) Jika anda memerlukan pembangunan pesat, pemprosesan data dan reka bentuk prototaip, pilih Python; 2) Jika anda memerlukan prestasi tinggi, latensi rendah dan kawalan perkakasan yang rapat, pilih C.

Dengan melabur 2 jam pembelajaran python setiap hari, anda dapat meningkatkan kemahiran pengaturcaraan anda dengan berkesan. 1. Ketahui Pengetahuan Baru: Baca dokumen atau tutorial menonton. 2. Amalan: Tulis kod dan latihan lengkap. 3. Kajian: Menyatukan kandungan yang telah anda pelajari. 4. Amalan Projek: Sapukan apa yang telah anda pelajari dalam projek sebenar. Pelan pembelajaran berstruktur seperti ini dapat membantu anda menguasai Python secara sistematik dan mencapai matlamat kerjaya.

Kaedah untuk belajar python dengan cekap dalam masa dua jam termasuk: 1. Semak pengetahuan asas dan pastikan anda sudah biasa dengan pemasangan Python dan sintaks asas; 2. Memahami konsep teras python, seperti pembolehubah, senarai, fungsi, dan lain -lain; 3. Menguasai penggunaan asas dan lanjutan dengan menggunakan contoh; 4. Belajar kesilapan biasa dan teknik debugging; 5. Memohon pengoptimuman prestasi dan amalan terbaik, seperti menggunakan komprehensif senarai dan mengikuti panduan gaya PEP8.

Python sesuai untuk pemula dan sains data, dan C sesuai untuk pengaturcaraan sistem dan pembangunan permainan. 1. Python adalah mudah dan mudah digunakan, sesuai untuk sains data dan pembangunan web. 2.C menyediakan prestasi dan kawalan yang tinggi, sesuai untuk pembangunan permainan dan pengaturcaraan sistem. Pilihan harus berdasarkan keperluan projek dan kepentingan peribadi.

Python lebih sesuai untuk sains data dan perkembangan pesat, manakala C lebih sesuai untuk prestasi tinggi dan pengaturcaraan sistem. 1. Sintaks Python adalah ringkas dan mudah dipelajari, sesuai untuk pemprosesan data dan pengkomputeran saintifik. 2.C mempunyai sintaks kompleks tetapi prestasi yang sangat baik dan sering digunakan dalam pembangunan permainan dan pengaturcaraan sistem.

Adalah mungkin untuk melabur dua jam sehari untuk belajar Python. 1. Belajar Pengetahuan Baru: Ketahui konsep baru dalam satu jam, seperti senarai dan kamus. 2. Amalan dan Amalan: Gunakan satu jam untuk melakukan latihan pengaturcaraan, seperti menulis program kecil. Melalui perancangan dan ketekunan yang munasabah, anda boleh menguasai konsep teras Python dalam masa yang singkat.

Python lebih mudah dipelajari dan digunakan, manakala C lebih kuat tetapi kompleks. 1. Sintaks Python adalah ringkas dan sesuai untuk pemula. Penaipan dinamik dan pengurusan memori automatik menjadikannya mudah digunakan, tetapi boleh menyebabkan kesilapan runtime. 2.C menyediakan kawalan peringkat rendah dan ciri-ciri canggih, sesuai untuk aplikasi berprestasi tinggi, tetapi mempunyai ambang pembelajaran yang tinggi dan memerlukan memori manual dan pengurusan keselamatan jenis.


Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

Video Face Swap
Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Artikel Panas

Alat panas

Muat turun versi mac editor Atom
Editor sumber terbuka yang paling popular

Dreamweaver Mac版
Alat pembangunan web visual

PhpStorm versi Mac
Alat pembangunan bersepadu PHP profesional terkini (2018.2.1).

mPDF
mPDF ialah perpustakaan PHP yang boleh menjana fail PDF daripada HTML yang dikodkan UTF-8. Pengarang asal, Ian Back, menulis mPDF untuk mengeluarkan fail PDF "dengan cepat" dari tapak webnya dan mengendalikan bahasa yang berbeza. Ia lebih perlahan dan menghasilkan fail yang lebih besar apabila menggunakan fon Unicode daripada skrip asal seperti HTML2FPDF, tetapi menyokong gaya CSS dsb. dan mempunyai banyak peningkatan. Menyokong hampir semua bahasa, termasuk RTL (Arab dan Ibrani) dan CJK (Cina, Jepun dan Korea). Menyokong elemen peringkat blok bersarang (seperti P, DIV),

EditPlus versi Cina retak
Saiz kecil, penyerlahan sintaks, tidak menyokong fungsi gesaan kod