l1=[1,2,3,4,5,6]
for i in l1:
要求1:print(i)
要求2:每一个线程的频率不一样,time.sleep(i)
总结:创建多个线程,每个线程打印频率不一样;为了便于区分,每次打印的时候,可以加一个前缀,类似“线程1”、“线程2”、“线程3”…
threading.Thread
类我们可以创建threading.Thread
类的实例来表示一个线程,然后调用它的start()
方法来启动线程。这种方法的特点是简单直观,但缺点是每个线程都需要创建一个Thread
对象,可能会占用较多的内存资源。
import threading
import time
def print_num(i):
print(f"线程{i}:{i}")
time.sleep(i)
l1 = [1, 2, 3, 4, 5, 6]
threads = []
for i in l1:
t = threading.Thread(target=print_num, args=(i,))
t.start()
threads.append(t)
for t in threads:
t.join()
concurrent.futures.ThreadPoolExecutor
类concurrent.futures.ThreadPoolExecutor
类提供了一个线程池,可以自动管理线程的创建和销毁。这种方法的优点是更加高效,因为它可以避免频繁地创建和销毁线程。此外,它还提供了submit()
方法,可以方便地提交任务到线程池。
from concurrent.futures import ThreadPoolExecutor
import time
def print_num(i):
print(f"线程{i}:{i}")
time.sleep(i)
l1 = [1, 2, 3, 4, 5, 6]
with ThreadPoolExecutor(max_workers=len(l1)) as executor:
for i in l1:
executor.submit(print_num, i)
queue.Queue
类queue.Queue
类提供了一个线程安全的队列,我们可以将任务放入队列中,然后让多个线程从队列中取出任务并执行。这种方法的优点是可以实现任务的生产者-消费者模型,适用于需要处理大量任务的场景。
import queue
import threading
import time
def worker(q):
while True:
i = q.get()
if i is None:
break
print(f"线程{i}:{i}")
time.sleep(i)
q.task_done()
l1 = [1, 2, 3, 4, 5, 6]
q = queue.Queue()
threads = []
for i in l1:
q.put(i)
for i in range(len(l1)):
t = threading.Thread(target=worker, args=(q,))
t.start()
threads.append(t)
q.join()
for t in threads:
t.join()
总结:以上三种方法都可以实现多线程,但各有优劣。使用threading.Thread
类的方法简单直观,但可能占用较多内存;使用concurrent.futures.ThreadPoolExecutor
类的方法更加高效,适合处理大量任务;使用queue.Queue
类的方法可以实现生产者-消费者模型,适用于需要处理大量任务的场景。在实际使用中,我们可以根据具体需求选择合适的方法。
案例1中如何持续打印?用三种方法实现。
threading.Thread
类import threading
import time
def print_num(i):
while True:
print(f"线程{i}:{i}")
time.sleep(i)
l1 = [1, 2, 3, 4, 5, 6]
threads = []
for i in l1:
t = threading.Thread(target=print_num, args=(i,))
t.start()
threads.append(t)
for t in threads:
t.join()
concurrent.futures.ThreadPoolExecutor
类from concurrent.futures import ThreadPoolExecutor
import time
def print_num(i):
while True:
print(f"线程{i}:{i}")
time.sleep(i)
l1 = [1, 2, 3, 4, 5, 6]
with ThreadPoolExecutor(max_workers=len(l1)) as executor:
for i in l1:
executor.submit(print_num, i)
queue.Queue
类import queue
import threading
import time
def worker(q, stop_event, keep_working):
while keep_working: # 使用全局变量来控制是否继续工作
try:
i = q.get(timeout=1) # 设置超时时间,防止线程卡在q.get()上
if i is None:
break
print(f"线程{i}:{i}")
time.sleep(i)
q.task_done()
except queue.Empty:
pass # 如果队列为空,则继续等待新任务
l1 = [1, 2, 3, 4, 5, 6]
q = queue.Queue()
stop_event = threading.Event() # 创建一个事件对象来控制线程的停止
keep_working = True # 全局变量,控制线程是否继续工作
threads = []
# 将任务添加到队列中,并且可以一直添加
for i in range(1000): # 添加更多的任务到队列中
q.put(l1[i % len(l1)])
for i in range(len(l1)):
t = threading.Thread(target=worker, args=(q, stop_event, keep_working))
t.start()
threads.append(t)
# 在某个时刻,当你想要停止线程时
# stop_event.set() # 设置事件,使得worker中的循环结束,从而停止线程
# keep_working = False # 设置全局变量,控制线程是否继续工作
# 等待队列中的任务被处理完
q.join()
# 停止工作线程
for i in range(len(l1)):
q.put(None)
for t in threads:
t.join()
在这个修改后的代码中,我们添加了一个全局变量 keep_working
来控制线程是否继续工作。当 keep_working
为 True
时,线程会一直工作;当它为 False
时,线程会停止工作。你可以通过设置 keep_working = False
来停止所有线程。
threading.Thread
类的方法使用threading.Thread
类创建线程的方法简单直观,可以直接实例化一个Thread
对象,然后调用其start()
方法启动线程。这种方法的优势在于代码简洁易懂,易于调试和维护。但是,它的缺点也很明显:
Thread
类没有提供线程池的功能,因此需要手动管理线程的创建、启动、销毁等操作。这在处理大量任务时会增加编程复杂度和出错概率。import threading
def worker(arg):
# 执行任务
pass
for i in range(10):
t = threading.Thread(target=worker, args=(i,))
t.start()
concurrent.futures.ThreadPoolExecutor
类的方法ThreadPoolExecutor
类提供了一个线程池,可以有效地管理和复用线程资源。相比于Thread
类,它具有以下优势:
submit()
方法提交任务,并返回一个Future
对象,方便后续对任务状态的查询和结果的获取。然而,ThreadPoolExecutor
也有一些局限性:
Thread
类,ThreadPoolExecutor
的使用相对复杂,需要熟悉其API和工作原理。from concurrent.futures import ThreadPoolExecutor
def worker(arg):
# 执行任务
pass
with ThreadPoolExecutor(max_workers=5) as executor:
futures = [executor.submit(worker, i) for i in range(10)]
queue.Queue
类的方法Queue
类提供了一种线程安全的队列实现,可以实现生产者-消费者模型。这种模型适用于需要处理大量任务的场景,具有以下优势:
然而,Queue
类的使用也有一些局限性:
import queue
import threading
def producer(q):
for i in range(10):
q.put(i)
def consumer(q):
while True:
task = q.get()
if task is None:
break
# 执行任务
pass
q = queue.Queue()
producer_thread = threading.Thread(target=producer, args=(q,))
consumer_thread = threading.Thread(target=consumer, args=(q,))
producer_thread.start()
consumer_thread.start()
producer_thread.join()
q.put(None)
consumer_thread.join()
综上所述,在实际使用中,我们可以根据具体需求选择合适的方法。对于简单的多线程任务,可以使用threading.Thread
类;对于需要处理大量任务的场景,可以使用concurrent.futures.ThreadPoolExecutor
类或queue.Queue
类实现生产者-消费者模型。
案例1中,新增要求3:设置条件,如果打印超过i次,则关闭对应的线程,,且为了便于区分,,输出关闭了线程1,关闭了线程2 …类似的提示语句
threading.Thread
类import threading
import time
# 定义一个全局变量,用于记录每个线程打印的次数
count_dict = {}
def print_and_sleep(i, thread_name):
count = 0
while count < i:
print(f'{thread_name}: {i}')
time.sleep(i)
count += 1
count_dict[thread_name] = count
if count >= i:
print(f'关闭了{thread_name}')
l1 = [1, 2, 3, 4, 5, 6]
for index, i in enumerate(l1):
thread_name = f'线程{index+1}'
t = threading.Thread(target=print_and_sleep, args=(i, thread_name))
t.start()
concurrent.futures.ThreadPoolExecutor
类在Python的concurrent.futures
模块中,ThreadPoolExecutor
类可以用于并行执行线程。下面是使用ThreadPoolExecutor
的代码示例:
import concurrent.futures
import time
def print_and_sleep(i, thread_name):
count = 0
while count < i:
print(f'{thread_name}: {i}')
time.sleep(i)
count += 1
if count >= i:
print(f'关闭了{thread_name}')
with concurrent.futures.ThreadPoolExecutor() as executor:
l1 = [1, 2, 3, 4, 5, 6]
futures = [executor.submit(print_and_sleep, i, f'线程{i}') for i in l1]
for future in concurrent.futures.as_completed(futures):
print(f'已完成: {future}')
在这个示例中,我们使用with
语句创建了一个ThreadPoolExecutor
实例,然后使用submit
方法提交了多个任务到线程池中。as_completed
方法用于等待所有任务完成。
queue.Queue
类Python的queue
模块提供了一个线程安全的队列实现,可以用于多线程之间的通信和同步。以下是一个使用queue.Queue
的示例:
import threading
import queue
import time
def print_and_sleep(q, i, thread_name):
count = 0
while count < i:
item = q.get() # 从队列中获取一个任务
if item is None: # 如果队列中没有任务,则退出循环
break
print(f'{thread_name}: {item}')
time.sleep(i) # 休眠指定的时间
count += 1
q.task_done() # 通知队列任务已完成
if count >= i:
print(f'关闭了{thread_name}')
q.put(None) # 将一个None对象放入队列,表示线程结束
q = queue.Queue() # 创建一个队列对象
l1 = [1, 2, 3, 4, 5, 6]
for i in l1:
q.put(i) # 将任务放入队列中
threads = [] # 存储所有线程的列表
for index in range(len(l1)):
thread_name = f'线程{index+1}'
t = threading.Thread(target=print_and_sleep, args=(q, l1[index], thread_name))
threads.append(t) # 将线程添加到列表中
t.start() # 启动线程
q.join() # 等待所有任务完成
for t in threads: # 等待所有线程结束
t.join()
在这个示例中,我们创建了一个queue.Queue
对象,并向其中添加了多个任务。然后,我们为每个任务启动了一个线程,每个线程从队列中获取任务并执行。线程通过调用task_done
方法通知队列任务已完成,然后通过将一个None对象放入队列来标记线程结束。最后,我们使用join
方法等待所有任务和线程完成。