博客
关于我
Python 多线程学习(转)
阅读量:798 次
发布时间: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 url请求提示certificate verify failed unable to get local issuer certificate
查看>>
Python UTC 日期时间对象的 ISO 格式不包括 Z(祖鲁语或零偏移)
查看>>
python valueerror object2_python遇到错误记录
查看>>
python vars的作用
查看>>
Python vcrpy库:HTTP请求记录和重放
查看>>
Python virtualenv
查看>>
python vue3实现大文件分段续传(断点续传)--带暂停和继续功能
查看>>
Python WebDriver如何打印整个页面源(html)
查看>>
Python WebSocket自动化测试:构建高效接口测试框架
查看>>
Python Web开发
查看>>
Redis 配置文件杂项。
查看>>
Python web自动化测试 —— 文件上传
查看>>
Python web自动化测试 —— 文件上传!
查看>>
Python Web自动化测试开发环境搭建(附安装包与虚拟机环境)
查看>>
python win32api键盘_Python win32api.keybd_event模拟键盘输入
查看>>
python Windows显示当前鼠标坐标
查看>>
python Workbook 表格宽度
查看>>
python write报错a byte-like object is required.not str
查看>>
PYTHON调用大模型实现图片生成
查看>>
python yaml.dump 缩进错误
查看>>