python多线程-Semaphore(信号对象)

本文详细介绍了Python中Semaphore对象的工作原理,包括其计数器管理、acquire和release方法的使用,以及如何通过示例代码展示线程间的同步机制。

Semaphore(value=1)

Semaphore对象内部管理一个计数器,该计数器由每个acquire()调用递减,并由每个release()调用递增。计数器永远不会低于零,当acquire()发现计数器为零时,线程阻塞,等待其他线程调用release()
Semaphore对象支持上下文管理协议。
方法:
acquire(blocking=True, timeout=None)
获取信号。
blocking=True时:如果调用时计数器大于零,则将其减1并立即返回。如果在调用时计数器为零,则阻塞并等待,直到其他线程调用release()使其大于零。这是通过适当的互锁来完成的,因此如果多个acquire()被阻塞,release()将只唤醒其中一个,这个过程会随机选择一个,因此不应该依赖阻塞线程的被唤醒顺序。
返回值为True
blocking=False时,不会阻塞。如果调用acquire()时计数器为零,则会立即返回False.
如果设置了timeout参数,它将阻塞最多timeout秒。如果在该时间段内没有获取锁,则返回False,否则返回True

release()
释放信号,使计数器递增1。当计数器为零并有另一个线程等待计数器大于零时,唤醒该线程。

BoundedSemaphore(value=1)

实现有界信号对象。有界信号对象确保计数器不超过初始值value,否则抛出ValueError
大多数情况下,该对象用于保护有限容量的资源。

栗子:

# -*- coding:utf-8 -*-
import threading
import time


sem = threading.Semaphore(3)


class DemoThread(threading.Thread):

    def run(self):
        print('{0} is waiting semaphore.'.format(self.name))
        sem.acquire()
        print('{0} acquired semaphore({1}).'.format(self.name, time.ctime()))
        time.sleep(5)
        print('{0} release semaphore.'.format(self.name))
        sem.release()


if __name__ == '__main__':
    threads = []
    for i in range(4):
        threads.append(DemoThread(name='Thread-' + str(i)))

    for t in threads:
        t.start()

    for t in threads:
        t.join()

运行结果:

Thread-0 is waiting semaphore.
Thread-0 acquired semaphore(Thu Oct 25 20:33:18 2018).
Thread-1 is waiting semaphore.
Thread-1 acquired semaphore(Thu Oct 25 20:33:18 2018).
Thread-2 is waiting semaphore.
Thread-2 acquired semaphore(Thu Oct 25 20:33:18 2018).
Thread-3 is waiting semaphore.
Thread-0 release semaphore.
Thread-3 acquired semaphore(Thu Oct 25 20:33:23 2018).
Thread-1 release semaphore.
Thread-2 release semaphore.
Thread-3 release semaphore.

可以看到Thread-3是在Thread-0释放后才获得信号对象。

转载于:https://www.cnblogs.com/thunderLL/p/9852687.html

Python中,多线程编程是通过`threading`模块实现的,该模块提供了创建和管理线程的工具。多线程允许程序同时执行多个任务,从而提高响应能力和资源利用率。然而,由于Python的全局解释器锁(GIL)的存在,多线程在CPU密集型任务中并不能真正实现并行计算,但在I/O密集型任务中仍能显著提升性能。 ### 创建和启动线程 使用`threading.Thread`类可以创建线程对象,并通过调用其`start()`方法启动线程。以下是一个简单的示例: ```python import threading def worker(): print("Worker thread is running") # 创建线程对象 thread = threading.Thread(target=worker) # 启动线程 thread.start() # 等待线程结束 thread.join() ``` ### 线程同步 在多线程环境中,多个线程可能会同时访问共享资源,导致数据不一致或竞态条件。为了解决这个问题,可以使用线程同步机制,如锁(Lock)、条件变量(Condition)和信号量(Semaphore)等。例如,使用`threading.Lock`来确保同一时间只有一个线程访问共享资源: ```python import threading # 创建锁对象 lock = threading.Lock() shared_resource = 0 def increment(): global shared_resource for _ in range(100000): lock.acquire() shared_resource += 1 lock.release() # 创建多个线程 threads = [threading.Thread(target=increment) for _ in range(4)] for thread in threads: thread.start() for thread in threads: thread.join() print(f"Final value of shared resource: {shared_resource}") ``` ### 线程间通信 除了锁之外,还可以使用`threading.Condition`来进行线程间的协调。条件变量允许一个或多个线程等待某个条件成立,然后被通知继续执行。以下是一个使用条件变量的示例: ```python import threading condition = threading.Condition() resource_available = False def consumer(): with condition: while not resource_available: condition.wait() # 使用资源 print("Resource is being used") def producer(): global resource_available with condition: resource_available = True condition.notify_all() # 创建并启动线程 consumer_thread = threading.Thread(target=consumer) producer_thread = threading.Thread(target=producer) consumer_thread.start() producer_thread.start() consumer_thread.join() producer_thread.join() ``` ### 多线程与性能优化 尽管多线程在I/O密集型任务中非常有效,但在CPU密集型任务中,由于GIL的限制,多线程并不能充分利用多核处理器的优势。对于这类任务,推荐使用`multiprocessing`模块来实现真正的并行计算。 在设计多线程程序时,还需要注意以下几点: - **避免死锁**:确保每个线程获取锁的顺序一致,以防止死锁。 - **合理分配线程数量**:过多的线程会导致上下文切换开销增加,反而降低性能。 - **使用线程池**:可以使用`concurrent.futures.ThreadPoolExecutor`来简化线程管理,提高效率。 ### 示例:多线程下载文件 下面是一个使用多线程进行文件下载的示例,展示了如何并发地执行I/O密集型任务: ```python import threading import requests def download_file(url, filename): with requests.get(url, stream=True) as r: r.raise_for_status() with open(filename, 'wb') as f: for chunk in r.iter_content(chunk_size=8192): if chunk: f.write(chunk) print(f"{filename} downloaded") urls = [ "https://example.com/file1.txt", "https://example.com/file2.txt", "https://example.com/file3.txt" ] filenames = ["file1.txt", "file2.txt", "file3.txt"] threads = [] for url, filename in zip(urls, filenames): thread = threading.Thread(target=download_file, args=(url, filename)) threads.append(thread) thread.start() for thread in threads: thread.join() ``` 通过上述方法,可以在Python中有效地使用多线程编程[^1]。对于更复杂的并发需求,还可以考虑使用高级库如`asyncio`来进行异步编程,或者使用`concurrent.futures`模块提供的高级接口来简化并发任务的管理[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值