目录
1, 什么是进程
2, 什么是线程
3, 什么是GIL
3-1, GIL设置流程
4, threading模块
4-1, threading模块 VS thread模块
4-2, Thread类的方法
4-3, Thread(target=函数名, args=(...))创建多线程
4-3, Thread(target=类实例, args=(...))创建多线程
4-3, Thread(target=Thread子类实例, args=(...))创建多线程
5, queue模块
5-1, queue模块方法
5-2,线程共享数据举例
进程是程序的一次执行,每个进程都有自己独立的地址空间,内存,数据栈以及记录其运行轨迹的辅助数据
一个进程中可以有多个线程,一个进程中多个线程共享相同的运行环境,数据空间
GIL叫着全局解释锁,对python解释器的的访问由GIL来控制,通过GIL保证了同一时刻,只能有一个python线程运行
1, 设置GIL
2, 切换到一个线程中去运行指定数量的字节码,线程主动让出控制(处于等待状态时,线程主动让出控制)
3, 把步骤2的线程设置为挂起状态
4, 解锁GIL
5, 重复以上步骤
thread模块不支持守护线程,当主线程退出时,所有的子程序都会被强制退出
threading模块支持守护线程,主线程会等待所有子线程完成后,才会退出;
threading模块,若存在守护线程,则主线程不用等待守护线程退出
strat():线程执行
In [6]: class MyThread(threading.Thread):
...: def __init__(self, func, args):
...: super(MyThread, self).__init__()
...: self.func = func
...: self.args = args
...: def run(self):
...: self.func(*self.args)
...:
In [7]: def func():
...: print("haha")
...:
In [8]: t = MyThread(func, ())
# 启动线程
In [9]: t.start()
haha
In [10]:
run():定义线程的功能函数(一般会被子类重写)
In [6]: class MyThread(threading.Thread):
...: def __init__(self, func, args):
...: super(MyThread, self).__init__()
...: self.func = func
...: self.args = args
# 定义线程的功能函数
# 在继承threading.Thread时,需要重新定义run函数
...: def run(self):
...: self.func(*self.args)
join(timeout=None):等待线程结束,若设置timeout, 则等待timeout后线程结束
getName():获取线程的名称,该方法已过期,获取线程的名称使用"线程.name"方法获取
In [11]: t.name
Out[11]: 'Thread-1'
setName():设置线程的名称, 该方法以过期,通过t.name="线程名字"来给线程重命名
# 设置线程t的名称为:Thread1_1
In [22]: t.name = 'thread1_1'
In [23]: t.name
Out[23]: 'thread1_1'
isAlive():判断线程是否存活,是返回True,否则返回False, 该方法已过期,使用新方法:
"t.is_alive()"
In [14]: t.is_alive()
Out[14]: False
isDeamon():判断线程是否是守护线程,是则返回True,否则返回False,该方法已过期,使用新方法"t.daemon"
In [16]: t.daemon
Out[16]: False
setDeamon(True):设置线程为守护线程
# 设置线程t为守护线程,需要在线程启动前进行设置
In [20]: t.setDaemon(True)
:1: DeprecationWarning: setDaemon() is deprecated, set the daemon attribute instead
t.setDaemon(True)
In [21]: t.daemon
Out[21]: True
#! /usr/bin/env python
# -*- coding:utf-8 -*-
import threading
from time import ctime, sleep
def loop(nloop, nsec):
print("start loop %s at %s" % (nloop, ctime()))
sleep(nsec)
print("loop %s done at: %s" % (nloop, ctime()))
def main():
print("strating at:", ctime())
loops = [4, 2]
nloops = range(len(loops))
thread_list = []
# 创建线程池
for i in nloops:
# target传入目标函数名,args为目标函数参数
# 注意:若目标函数没有参数,也需要传入一个空元组
t = threading.Thread(target=loop, args=(i, loops[i]))
thread_list.append(t)
# 通过start()方法启动线程池
for t in thread_list:
t.start()
# 通过join()方法等待线程池结束
# join()方法是一旦线程启动后,就会一直运行,直到线程的函数结束,退出为止
# 所以join()方法可以不用显示调用
for t in thread_list:
t.join()
print("all done at:", ctime())
if __name__ == "__main__":
main()
# 输出结果:
strating at: Tue Aug 22 12:19:06 2023
start loop 0 at Tue Aug 22 12:19:06 2023
start loop 1 at Tue Aug 22 12:19:06 2023
loop 1 done at: Tue Aug 22 12:19:08 2023
loop 0 done at: Tue Aug 22 12:19:10 2023
all done at: Tue Aug 22 12:19:10 2023
#! /usr/bin/env python
# -*- coding:utf-8 -*-
import threading
from time import ctime, sleep
class ThreadFun(object):
def __init__(self, func, args):
self.func = func
self.args = args
def __call__(self):
'''该方法的作用是类的实例像函数一样调用'''
self.func(*self.args)
def loop(nloop, nsec):
print("start loop %s at %s" % (nloop, ctime()))
sleep(nsec)
print("loop %s done at: %s" % (nloop, ctime()))
def main():
print("strating at:", ctime())
loops = [4, 2]
nloops = range(len(loops))
thread_list = []
# 创建线程池
for i in nloops:
# target传入类实例,这里没有args参数
t = threading.Thread(target=ThreadFun(loop, (i, loops[i])))
thread_list.append(t)
# 通过start()方法启动线程池
for t in thread_list:
t.start()
for t in thread_list:
t.join()
print("all done at:", ctime())
if __name__ == "__main__":
main()
# 输出结果
strating at: Wed Aug 23 11:51:02 2023
start loop 0 at Wed Aug 23 11:51:02 2023
start loop 1 at Wed Aug 23 11:51:02 2023
loop 1 done at: Wed Aug 23 11:51:04 2023
loop 0 done at: Wed Aug 23 11:51:06 2023
all done at: Wed Aug 23 11:51:06 2023
#! /usr/bin/env python
# -*- coding:utf-8 -*-
import threading
from time import ctime, sleep
class MyThread(threading.Thread):
def __init__(self, func, args):
super(MyThread, self).__init__()
self.func = func
self.args = args
def run(self):
"""定义线程运行的功能函数"""
self.func(*self.args)
def loop(nloop, nsec):
print("start loop %s at %s" % (nloop, ctime()))
sleep(nsec)
print("loop %s done at: %s" % (nloop, ctime()))
def main():
print("strating at:", ctime())
loops = [4, 2]
nloops = range(len(loops))
thread_list = []
# 创建线程池
for i in nloops:
# 注意:这里没有target参数,直接是threading.Thread子类的实例
t = MyThread(loop, (i, loops[i]))
thread_list.append(t)
# 通过start()方法启动线程池
for t in thread_list:
t.start()
for t in thread_list:
t.join()
print("all done at:", ctime())
if __name__ == "__main__":
main()
通过queue模块能让线程与线程之间共享数据
QUEUE():创建一个QUEUE对象, QUEUE中的对象是先进先出
# 创建大小为32的QUEUE对象
In [1]: from queue import Queue
In [2]: q = Queue(32)
q.put(item, timeout):将对象item放入到queue中, timeout为超时时间
In [2]: q = Queue(32)
In [3]: q.put('xxxx')
q.get(timeout):获取QUEUE中的对象, timeout为超时时间
In [6]: q.get()
Out[6]: 'xxxx'
q.full():若QUEUE队列已满,则返回True,否则返回False
In [8]: q.full()
Out[8]: False
q.empty():若QUEUE队列为空,则返回True,否则返回False
In [7]: q.empty()
Out[7]: False
q.qsize():返回当前QUEUE队列的大小
In [9]: q.qsize()
Out[9]: 1
from threading import Thread
from queue import Queue
class MyThread(Thread):
"""自定义多线程类"""
def __init__(self, func, args):
super(MyThread, self).__init__()
self.func = func
self.args = args
def run(self):
self.func(*self.args)
def read_queue(q):
"""从QUEUE中取出一个对象"""
print('get object from q:', q.get())
print("now qsize:", q.qsize())
def write_queue(q, item):
"""写入一个对象到QUEUE中"""
print('write object in q:')
# 将item放入Queue中
q.put(item)
print("now qsize:", q.qsize())
if __name__ == "__main__":
func_list = [write_queue, read_queue]
nfuncs = range(len(func_list))
q = Queue(32)
thread_list = []
for i in range(5):
t = MyThread(write_queue, (q, ('object_%s' % i)))
thread_list.append(t)
for i in range(3):
t = MyThread(read_queue, (q, ))
thread_list.append(t)
for i in range(len(thread_list)):
thread_list[i].start()
for i in nfuncs:
thread_list[i].join()