- python线程概念:
线程也叫轻量级进程,是操作系统能够进行运算调度的最小单位,它被包涵在进程之中,是进程中的实际运作单位。线程不拥有竞争系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其他线程共享进程所拥有的全部资源。一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行。 - 使用多线程的优处:
进程之间不能共享内存,但线程之间共享内存非常容易。
操作系统在创建进程时,需要为该进程重新分配系统资源,但创建线程的代价则小得多。线程比进程的并发性高。
python语言内置了多线程功能支持,而不是单纯地作为底层操作系统的调度方式,从而简化了python的多线程编程。
线程主要是_thread和threading模块
标准库_thread模块其实是start_new_thread方法:语法格式_thread.start_new_thread(function,
args[,kwargs]) 参数列表args是执行函数,可选的kwargs参数只指定关键字参数的字典。
- 普通创建
import time
import datetime
import _thread
date_time_format = "%H:%M:%S"
def get_time_str():
now = datetime.datetime.now()
return datetime.datetime.strftime(now, date_time_format) # 时间格式化为ISO来输出
def thread_function(thread_id):
print("Thread %d\t start at %s" % (thread_id, get_time_str())) # \t空四个字符(\n\t换行空四个字符),%d对应线程号thread_id
# %s对应时间get_time_str()
print("Thread %d\t sleeping" % thread_id)
time.sleep(4) # sleep函数推迟调用线程的运行,通过参数secs指秒数来表示线程挂起的时间。
print("Thread %d\t finish at %s" % (thread_id, get_time_str()))
def main():
print("Main thread start at %s" % get_time_str())
for i in range(5):
# _thread模块中start_new_thread方法提供简单的多线程机制,单个线程执行时别的线程也在同步执行
_thread.start_new_thread(thread_function, (i,))
time.sleep(6) # 主线程添加secs=6目的是让主线程不要立马执行完退出,主线程退出则其它线程无论是否执行完都要被强制退出
print("Main thread finish at %s" % get_time_str())
if __name__ == "__main__":
main()
- 输出为:结果是顺序的,但是可能出现乱序,两行输出结果相叠的情况。
Main thread start at 21:57:02
Thread 0 start at 21:57:02
Thread 0 sleeping
Thread 4 start at 21:57:02Thread 3 start at 21:57:02
Thread3 sleeping
Thread 1 start at 21:57:02Thread 2 start at 21:57:02
Thread 2 sleepingThread 1 sleeping
Thread 4 sleeping
Thread 4 finish at 21:57:06Thread 2 finish at 21:57:06
Thread 1 finish at 21:57:06Thread 0 finish at 21:57:06Thread 3 finish at 21:57:06
Main thread finish at 21:57:08
- _thread.allocate_lock方法返回一个Lock对象:常见方法有acquire、release和locked
由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,当多个线程同时修改同一条数据时可能会出现脏数据, 所以出现了线程锁(主线程可以在其它线程执行完后立即退出),即同一时刻允许一个线程执行操作。线程锁用于锁定资源,可以定义多个锁,像下面的代码,当需要独占 某一个资源时,任何一个锁都可以锁定这个资源,就好比你用不同的锁都可以把这个相同的门锁住一样。 由于线程之间是进行随机调度的,如果有多个线程同时操作一个对象,如果没有很好地保护该对象,会造成程序结果的不可预期, 我们因此也称为“线程不安全”。 为了防止上面情况的发生,就出现了互斥锁(Lock)
import time
import datetime
import _thread
date_time_format = "%H:%M:%S"
def get_time_str():
now = datetime.datetime.now()
return datetime.datetime.strftime(now, date_time_format) # 时间格式化为ISO来输出
def thread_function(thread_id, lock):
print("Thread %d\t start at %s" % (thread_id, get_time_str())) # \t空四个字符(\n\t换行空四个字符),%d对应线程号thread_id
# %s对应时间get_time_str()
print("Thread %d\t sleeping" % thread_id)
time.sleep(4) # sleep函数推迟调用线程的运行,通过参数secs指秒数来表示线程挂起的时间。
print("Thread %d\t finish at %s" % (thread_id, get_time_str()))
lock.release() # release方法用于释放锁,释放前线程必须处于锁定状态,可以不在同一个线程中释放锁.
def main():
print("Main thread start at %s" % get_time_str())
locks = []
for i in range(5):
lock = _thread.allocate_lock()
lock.acquire() # 无条件获取锁定Look对象,等待它被另一个线程释放(一次只有一个线程可以获取锁定)
locks.append(lock)
for i in range(5):
_thread.start_new_thread(thread_function, (i, locks[i])) # 启动一个线程并返回其标识符
time.sleep(1)
for i in range(5):
while locks[i].locked(): # 用于返回锁的状态,如果已被某个线程锁定,则返回True否则返回False
time.sleep(1)
print("Main thread finish at %s" % get_time_str())
if __name__ == "__main__":
main()
输出为:
Main thread start at 22:43:28
Thread 0 start at 22:43:28
Thread 0 sleeping
Thread 1 start at 22:43:29
Thread 1 sleeping
Thread 2 start at 22:43:30
Thread 2 sleeping
Thread 3 start at 22:43:32
Thread 3 sleeping
Thread 0 finish at 22:43:32
Thread 4 start at 22:43:33
Thread 4 sleeping
Thread 1 finish at 22:43:34
Thread 2 finish at 22:43:34
Thread 3 finish at 22:43:36
Thread 4 finish at 22:43:37
Main thread finish at 22:43:38
- 自定义线程:继承threading.Thread来定义线程类,其本质是重构Thread类中的run方法
import time
import datetime
import threading
date_time_format = "%H:%M:%S"
def get_time_str():
now = datetime.datetime.now()
return datetime.datetime.strftime(now, date_time_format) # 时间格式化为ISO来输出
class MyThread(threading.Thread): # 子类调用父类threading.Thread
def __init__(self, thread_id):
super(MyThread, self).__init__() # 用super()方法来调用父类的__init__()构造方法
self.thread_id = thread_id # 初始化属性
def run(self):
print("Thread %d\t start at %s" % (self.thread_id, get_time_str())) # \t空四个字符(\n\t换行空四个字符),%d对应线程号thread_id
# %s对应时间get_time_str()
print("Thread %d\t sleeping" % self.thread_id)
time.sleep(4) # sleep函数推迟调用线程的运行,通过参数secs指秒数来表示线程挂起的时间。
print("Thread %d\t finish at %s" % (self.thread_id, get_time_str()))
def main():
print("Main thread start at %s" % get_time_str())
threads = []
# 创建线程
for i in range(5):
thread = MyThread(i) # 创建子类MyThread的对象并赋予参数i
threads.append(thread) # 用append()在列表threads后面追加元素
# 启动线程
for i in range(5):
threads[i].start()
time.sleep(1)
# 等待线程执行完毕
for i in range(5):
threads[i].join()
print("Main thread finish at %s" % get_time_str())
if __name__ == "__main__":
main()
输出为:
Main thread start at 22:16:33
Thread 0 start at 22:16:33
Thread 0 sleeping
Thread 1 start at 22:16:34
Thread 1 sleeping
Thread 2 start at 22:16:35
Thread 2 sleeping
Thread 3 start at 22:16:36
Thread 3 sleeping
Thread 0 finish at 22:16:37
Thread 4 start at 22:16:37
Thread 4 sleeping
Thread 1 finish at 22:16:38
Thread 2 finish at 22:16:39
Thread 3 finish at 22:16:40
Thread 4 finish at 22:16:41
Main thread finish at 22:16:41
- 队列:Queue类实现了一个基本的先进先出(FIFO)容器,使用put()将元素添加到队列尾端,使用get()从队列尾部移除元素。
from queue import Queue
q = Queue() # 创建Queue()的对象
for i in range(5):
q.put(i) # 将元素加入q序列的尾端
while not q.empty(): # while语句满足队列不为空执行下面代码
print(q.get()) # 将元素从队列中移除并输出来
输出为:
0
1
2
3
4