博客
关于我
Python 多线程学习(转)
阅读量:796 次
发布时间:2023-03-07

本文共 3182 字,大约阅读时间需要 10 分钟。

全局解释器锁(GIL)是Python解释器的核心机制,它限制了并发线程对Python对象的访问,确保线程安全。GIL每100字节码指令周期进行一次锁释放和重新获取,尽管这一机制有效防止了并发安全问题,但也限制了多线程程序的性能表现。

理解线程与进程的区别是掌握线程编程的第一步。线程与进程在资源共享方面存在根本差异:线程共享同一内存空间和资源,但各线程间的状态一致;而进程则拥有独立的内存空间和资源。线程的轻量级特性使其在资源利用上更高效,但同时也带来了竞态条件、死锁等复杂问题。

Python线程的基本使用方法可以通过以下示例来体现:

import threadingimport datetimeclass ThreadClass(threading.Thread):    def run(self):        now = datetime.datetime.now()        print(f"{self.getName()} says Hello World at time: {now}")        t1 = ThreadClass()t2 = ThreadClass()t1.start()t2.start()

输出结果显示,两个线程能够同时输出"Hello World",并带有时间戳。这个简单的示例展示了线程的基本使用方式,类ThreadClass通过继承threading.Thread创建了一个线程池,run方法定义了线程执行的操作。

线程编程的复杂性在于需要处理共享资源的安全访问。队列模块提供了一种简便的解决方案,通过将任务传递给各个线程,简化了线程间的通信与同步。在以下示例中,使用队列实现了并发访问URL的处理:

import urllib2import timeimport Queueimport threadinghosts = ["http://yahoo.com", "http://baidu.com", "http://amazon.com",        "http://ibm.com", "http://apple.com"]queue = Queue.Queue()class ThreadUrl(threading.Thread):    def __init__(self, queue):        threading.Thread.__init__(self)        self.queue = queue    def run(self):        while True:            host = self.queue.get()            url = urllib2.urlopen(host)            print(url.read(1024))            self.queue.task_done()            start = time.time()def main():    for _ in range(5):        t = ThreadUrl(queue)        t.setDaemon(True)        t.start()        for host in hosts:        queue.put(host)        queue.join()main()print(f"Elapsed Time: {time.time() - start}")

在这个示例中,主线程创建了5个守护线程池,负责处理URL请求。每个线程从队列中获取URL,处理完毕后调用task_done。主线程通过队列.join()等待所有任务完成。

线程编程的高级特性可以通过组合多个队列实现更复杂的任务流程。例如,下面的示例展示了如何将多个队列用于数据处理:

import Queueimport threadingimport urllib2from BeautifulSoup import BeautifulSouphosts = ["http://yahoo.com", "http://baidu.com", "http://amazon.com",        "http://ibm.com", "http://apple.com"]queue = Queue.Queue()out_queue = Queue.Queue()class ThreadUrl(threading.Thread):    def __init__(self, queue, out_queue):        threading.Thread.__init__(self)        self.queue = queue        self.out_queue = out_queue    def run(self):        while True:            host = self.queue.get()            url = urllib2.urlopen(host)            chunk = url.read()            self.out_queue.put(chunk)            self.queue.task_done()class DatamineThread(threading.Thread):    def __init__(self, out_queue):        threading.Thread.__init__(self)        self.out_queue = out_queue    def run(self):        while True:            chunk = self.out_queue.get()            soup = BeautifulSoup(chunk)            print(f"Found: {len(soup.findAll(['title']))} titles")            self.out_queue.task_done()def main():    for _ in range(5):        t = ThreadUrl(queue, out_queue)        t.setDaemon(True)        t.start()        for host in hosts:        queue.put(host)        for _ in range(5):        dt = DatamineThread(out_queue)        dt.setDaemon(True)        dt.start()        queue.join()    out_queue.join()main()print(f"Elapsed Time: {time.time() - start}")

在这个扩展示例中,使用了两个队列:一个用于分发URL请求,另一个用于存储和处理获取的网页内容。这种模式展示了如何通过多级队列实现任务流水线,提高了并发处理效率。

线程编程的关键在于正确管理共享资源和避免竞争条件。通过使用队列模块,可以显著降低线程编程的复杂性,实现更高效的资源利用。在实际应用中,选择线程还是进程取决于任务的特性,进程适合需要长时间运行或资源密集型任务,而线程适合需要频繁通信的轻量级任务。

转载地址:http://kiofk.baihongyu.com/

你可能感兴趣的文章
Python读取Excel的几种工具包(附Demo)
查看>>
Python 中的生成器是什么?
查看>>
Python 中的离线语音转文本
查看>>
Python读写json文件的简单实现
查看>>
Python 中的线程
查看>>
Python 中的继承机制是什么样的?
查看>>
python读写excel之xlrd&xlwt&xlutils组合
查看>>
Python 中的装饰器是什么?
查看>>
Python 中的装饰器是如何工作的,有哪些实际应用场景?
查看>>
python读excel
查看>>
Python 中读取 CSV 文件-ChatGPT4o作答
查看>>
Python 之 filecmp
查看>>
python请求html_使用Python请求获取HTML?
查看>>
Python 之匿名函数和偏函数
查看>>
python 之栈的实现
查看>>
python语音播放
查看>>
python语言:装饰器原理
查看>>
Python 交互式数据可视化详解
查看>>
python语言有哪些优点和缺点_Python有哪些优缺点,你了解吗?
查看>>
Python 从入门到精通:30天速成教程到底有多狠?你能坚持下来吗?
查看>>