线程篇
基本使用
python线程使用的两个模块为: _thread (不推荐再使用)、 threading
(查看threading的源码可以发现,threading实际是对_thread进一步的封装,官方将其称为 Low-level threading API,下面简单尝试使用_thread)
调用start_new_thread()函数生成新线程
函数声明:_thread.start_new_thread(function, args[, kwargs])
function: 子线程所执行的函数
args: 传递的参数,参数类型必须是元组
kwargs:可选参数
示例:
#!usr/bin/env python
#coding=utf-8
import _thread
import time
def func(t_name):
time.sleep(1)
print(t_name, 'end')
_thread.start_new_thread(func, ('my_thread_1',)) # 传递的参数必须是元组类型
print('main thread end')
time.sleep(2) # 暂停一下等待子线程,避免主线程结束后直接退出,看不到子线程的输出
输出
main thread end
my_thread_1 end
threading模块
需要 import threading
threading模块提供了比_thread模块更加高级别的方法,如下:
threading.active_count(): 返回当前运行的线程数量
threading.current_thread(): 返回当前运行的线程对象
threading.get_ident(): 返回当前运行的线程标识码
threading.enumerate(): 获取运作着的线程对象的列表(包含设置了daemon属性的后台线程)
threading.main_thread(): 获取主线程对象
threading模块包含Thread类来处理线程
函数声明:class threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)
(group: 官方预留的参数)
target: 子线程要执行的函数
name: 给子线程命名
args: 传递参数到要执行的函数中 (类型为元组)
daemon: 将线程设置为后台线程 1
Thread类包含的方法:
start(): 开始线程,它会安排在单独的控制线程中使该对象的run()方法被调用 (invoked) 2 (如果多次调用,会raise RuntimeError)
run(): 你可以在子类中重写这个方法,标准的run()方法会在构造器传递了target参数后调用它
join(timeout=None): 阻塞当前线程,直到等待调用了join()的线程结束,或到达设置的超时timeout的参数为止 (如果尝试加入当前线程 3,因为会发生死锁,join()会raise RuntimeError。在线程启动前调用join()也会报相同的错误)
name: 线程名
ident: 线程标识码 (如果线程未start(),则为None。实测线程结束后,ident值还存在)
is_alive(): 判断线程是否在运行
daemon: 是否为后台线程的属性值
isDaemon(): 判断是否为后台线程
函数形式
使用threading.Thread类实例化对象,再调用start()方法运行
示例:
#!usr/bin/env python
#coding=utf-8
import threading
import time
def func():
print(threading.current_thread().name, ' start')
time.sleep(1)
print(threading.current_thread().name, ' end')
t1 = threading.Thread(target=func) # 创建线程
t2 = threading.Thread(target=func)
t1.start() # 开始线程
t2.start()
# t1.join() # 等待该线程结束后,再往下执行
# t2.join()
print('main thread end') # 使用threading模块Thread类的线程,程序需要等待全部线程执行完后才退出
输出
Thread-1 start
Thread-2 start
main thread end
Thread-1 end
Thread-2 end
继承类的形式
通过继承threading.Thread类,可以重写run()方法,再实例化该类,调用start()方法运行
(继承Thread类,并不是非要重写run())
示例:
#!usr/bin/env python
#coding=utf-8
import threading
import time
class MyThread(threading.Thread):
def __init__(self, name):
threading.Thread.__init__(self)
self.name = name
def run(self):
print(self.name + ' start')
time.sleep(1)
print(self.name + ' end')
t1 = MyThread('thread1')
t2 = MyThread('thread2')
t1.start()
t2.start()
# t1.join()
# t2.join()
print('main thread end')
输出
thread1 start
thread2 start
main thread end
thread1 end
thread2 end
线程同步
当属于并发线程的多个操作尝试访问共享内存,并且至少有一个操作能修改数据的状态时,这时如果没有恰当的同步机制,可能会发生意外情况或bug。使用锁可以解决此问题。
当一个线程想要访问共享内存的某一部分区域时,它必须再使用前获取到该部分的锁。并在操作完后,要释放掉之前获取到的锁。
注意! 要避免死锁 4的情况发生
使用Lock实现线程同步
使用threading.Lock()实例化Lock锁对象
在共享资源操作的部分&