python的多线程由threading模块提供多线程的实现,python多线程的基础概念,包括GIL锁,如何线程的ID,如何启动线程,如何传入参数,如何创建后台线程, 如何使用join连接子线程并等待子线程全部结束。
python的多线程,并不是真正的多线程,因为有Global Interpreter Lock这个bug一般的全局锁存在,这使得同一时刻,只能有一个线程在执行。
需要注意的是,GIL锁并不是python语言的特性,它是实现CPython时引入的概念。一门语言的代码,可以由多种编译器来编译,比如C++的代码,你可以用GCC 来编译,也可以用Visual C++,同理,一段python代码也可以在不同的执行环境来执行,比如CPython,PyPy,JPython,这其中,JPython就没有GIL锁,由于CPython是默认的执行环境,因此,给大家造成了误会,以为python这门语言很蛋疼的弄了一个GIL锁。
由于有全局锁的存在,所以,python很难有效的利用多核,但也不是一点用处都没有了,在IO密集型的任务里,还是有用武之地的,比如你写一个多线程的爬虫,一个线程的请求发出去以后,需要等待服务器返回数据,其他的线程就可以继续执行了,充分利用网络IO。
有很多文章告诉你如何获取线程的id,方法就是threading.currentThread().ident ,但这是不对的,ident只是线程的标识,而非线程id,正确的做法是使用ctypes库获取,方法如下
import threading
import ctypes
SYS_gettid = 186
libc = ctypes.cdll.LoadLibrary('libc.so.6')
tid = libc.syscall(SYS_gettid)
print(tid)
print(threading.currentThread().ident)
上述代码要在linux环境下才能执行, 当然,你也可以将线程标识用于区分线程。
import threading
import time
def my_print():
for i in range(10):
print(i)
time.sleep(0.5)
t = threading.Thread(target=my_print)
t.start()
print('主线程结束')
你所看到的,是一个非常简单的启动多线程的方法
仰赖于python语言的简洁性,启动一个多线程非常的简单,程序输出结果
0
主线程结束
1
2
3
4
5
6
7
8
9
除了第3小节所展示的方法以外,还可以通过继承threading.Thread来创建一个线程
import threading
import time
def my_print():
for i in range(10):
print(i)
time.sleep(0.5)
class PringThread(threading.Thread):
def __init__(self, count):
super().__init__()
self.count = count
def run(self):
for i in range(self.count):
print(i)
time.sleep(0.5)
t = PringThread(10)
t.start()
print('主线程结束')
采用这种方法时,必须实现run方法
修改my_print方法
def my_print(count):
for i in range(count):
print(i)
time.sleep(0.5)
通过args向线程传入参数
t = threading.Thread(target=my_print, args=(5, ))
t.start()
print('主线程结束')
args需要传入一个元组,因此,尽管只有一个参数,也要写一个逗号
import threading
import time
def my_print(count):
for i in range(count):
print(i)
time.sleep(0.5)
t = threading.Thread(target=my_print, args=(5, ))
t.setDaemon(True)
t.start()
print('主线程结束')
使用setDaemon方法将线程设置为后台线程,这意味着,主线程就不会等待它结束,执行程序,输出结果为
0
主线程结束
线程启动后刚刚输出一个0,主线程就已经结束了,由于子线程是后台线程,因此输出内容不会在控制台上显示,如果你不喜欢主线程等待子线程运行的结果,那么就可以将子线程设置成后台线程
之前的示例代码中,启动线程后,立刻执行主线程里的代码,在实际应用中,通常,会使用join方法,等待子线程执行结束
import threading
import time
def my_print(n):
for i in range(n):
print(i)
time.sleep(0.5)
t_lst = []
for i in range(3):
t = threading.Thread(target=my_print,args=(5,))
t_lst.append(t)
for t in t_lst:
t.start()
for t in t_lst:
t.join()
print('主线程')
三个子线程都是用join()方法,只有他们都执行结束以后才会执行print('主线程'), 等待的时间是可以设置的,比如将上面的程序改为t.join(0.1),那么主线程会每个程序都等待0.1秒钟的时间,0.3秒钟以后,主线程就不再继续等了,开始执行自己的代码,如果不设置时间就表示一直等待,直到所有子线程结束
QQ交流群: 211426309