threading----线程

本文介绍Python3线程中常用的两个模块 _thread 和 threading,推荐使用 threading 模块。还阐述了线程同步的方法,如使用 Lock、Rlock、Condition 等对象,以及 Semaphore、Event 等的使用,同时介绍了一些获取线程信息的方法。

https://www.runoob.com/python3/python3-multithreading.html
https://www.cnblogs.com/chengd/articles/7770898.html
Python3 线程中常用的两个模块为:
_thread
threading(推荐使用)
thread 模块已被废弃。用户可以使用 threading 模块代替。所以,在 Python3 中不能再使用"thread" 模块。为了兼容性,Python3 将 thread 重命名为 “_thread”。

  1. threading.Lock()
    如果多个线程共同对某个数据修改,则可能出现不可预料的结果,为了保证数据的正确性,需要对多个线程进行同步。
    使用 Thread 对象的 Lock 和 Rlock 可以实现简单的线程同步,这两个对象都有 acquire 方法和 release 方法,对于那些需要每次只允许一个线程操作的数据,可以将其操作放到 acquire 和 release 方法之间。

  2. threading.Rlock()
    RLock允许在同一线程中被多次acquire。而Lock却不允许这种情况。注意:如果使用RLock,那么acquire和release必须成对出现,即调用了n次acquire,必须调用n次的release才能真正释放所占用的琐。

  3. threading.Condition()
    可以把Condiftion理解为一把高级的琐,它提供了比Lock, RLock更高级的功能,允许我们能够控制复杂的线程同步问题。threadiong.Condition在内部维护一个琐对象(默认是RLock),可以在创建Condigtion对象的时候把琐对象作为参数传入。Condition也提供了acquire, release方法,其含义与琐的acquire, release方法一致,其实它只是简单的调用内部琐对象的对应的方法而已。Condition还提供wait方法、notify方法、notifyAll方法(特别要注意:这些方法只有在占用琐(acquire)之后才能调用,否则将会报RuntimeError异常。):

    acquire()/release():获得/释放 Lock

    wait([timeout]):线程挂起,直到收到一个notify通知或者超时(可选的,浮点数,单位是秒s)才会被唤醒继续运行。wait()必须在已获得Lock前提下才能调用,否则会触发RuntimeError。调用wait()会释放Lock,直至该线程被Notify()、NotifyAll()或者超时线程又重新获得Lock.

    notify(n=1):通知其他线程,那些挂起的线程接到这个通知之后会开始运行,默认是通知一个正等待该condition的线程,最多则唤醒n个等待的线程。notify()必须在已获得Lock前提下才能调用,否则会触发RuntimeError。notify()不会主动释放Lock。

    notifyAll(): 如果wait状态线程比较多,notifyAll的作用就是通知所有线程(这个一般用得少)。

  4. threading.Semaphore和BoundedSemaphore
    Semaphore:Semaphore 在内部管理着一个计数器。调用 acquire() 会使这个计数器 -1,release() 则是+1(可以多次release(),所以计数器的值理论上可以无限).计数器的值永远不会小于 0,当计数器到 0 时,再调用 acquire() 就会阻塞,直到其他线程来调用release()。

  5. threading.Event
    事件处理的机制:全局定义了一个“Flag”,如果“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞;如果“Flag”值为True,那么执行event.wait 方法时便不再阻塞。

    clear:将“Flag”设置为False
    set:将“Flag”设置为True
    用 threading.Event 实现线程间通信,使用threading.Event可以使一个线程等待其他线程的通知,我们把这个Event传递到线程对象中,

    Event默认内置了一个标志,初始值为False。一旦该线程通过wait()方法进入等待状态,直到另一个线程调用该Event的set()方法将内置标志设置为True时,该Event会通知所有等待状态的线程恢复运行。

  6. threading.active_count():返回当前存活的线程对象的数量;通过计算len(threading.enumerate())长度而来。

  7. threading.current_thread():返回当前线程对象

  8. threading.enumerate():返回当前存在的所有线程对象的列表

  9. threading.get_ident():返回线程pid

  10. threading.main_thread():返回主线程对象,类似 threading.current_thread();只不过一个是返回当前线程对象,一个是返回主线程对象

在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、付费专栏及课程。

余额充值