Python3 threading.Thread 如何线程间通信 queque

由于GIL的存在,多线程进行cpu密集型操作并不能提高执行效率(针对 python2),我们修改

程序构架

1 使用多个DownloadThread线程进行下载(I/O操作)

2 使用一个ConvertThread线程进行转换(CPU操作)

3 下载线程把下载数据 安全地传递给转换线程

解决方案:

使用标准库中的Queue.Queue,它是一个线程安全的队列

Download线程把下载数据放入队列 ,Convert线程从队列里提取数据

Python
# -*- coding: utf-8 -*- import csv from xml.etree.cElementTree import ElementTree, Element import requests from io import StringIO # 以下为生产者-消费者模型 # 一个进程的多个线程使用的是同一个地址空间 # 实现下载线程 from <span class="wp_keywordlink_affiliate"><a href="https://www.168seo.cn/tag/threading" title="View all posts in threading" target="_blank">threading</a></span> import Thread from <span class="wp_keywordlink_affiliate"><a href="https://www.168seo.cn/tag/queue" title="View all posts in queue" target="_blank">queue</a></span> import Queue class DownloadThread(Thread): def __init__(self, sid, <span class="wp_keywordlink_affiliate"><a href="https://www.168seo.cn/tag/queue" title="View all posts in queue" target="_blank">queue</a></span>): Thread.__init__(self) self.sid = sid self.url = 'http://table.finance.yahoo.com/table.csv?s=%s.sz' self.url %= str(sid).rjust(6, '0') self.queue = queue @staticmethod def download(url): response = requests.get(url, timeout=3) if response.ok: return (StringIO(str(response.content))) # 返回一个支持文件操作的内存对象 def run(self): print('Downloading ... (%d)' % self.sid) # 1下载 data = self.download(self.url) # 2 将数据传给转换线程 sid, data # 加锁安全 self.queue.put((self.sid, data)) class ConvertThread(Thread): def __init__(self, queue): Thread.__init__(self) self.queue = queue def csvToXml(self, scsv, fxml): reader = csv.reader(scsv) headers = next(reader) headers = map(lambda h: h.replace(' ', ''), headers) root = Element('Data') for row in reader: eRow = Element('Row') root.append(eRow) for tag, text in zip(headers, row): e = Element(tag) e.text = text eRow.append(e) et = ElementTree(root) et.write(fxml) def run(self): while True: sid, data = self.queue.get() print('Converting to XML ... (%d)' % sid) if sid == -1: break if data: fname = str(sid).rjust(6, '0') + '.xml' with open(fname, 'wb') as wf: self.csvToXml(data, wf) if __name__ == '__main__': q = Queue() dThreads = [DownloadThread(i, q) for i in range(1, 11)] cThreads = ConvertThread(q) for t in dThreads: t.start() cThreads.start() for t in dThreads: t.join() # http://blog.youkuaiyun.com/u013679490/article/details/54767220 q.put((-1, None))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# -*- coding: utf-8 -*-
import csv
from xml . etree . cElementTree import ElementTree , Element
import requests
from io import StringIO
# 以下为生产者-消费者模型
# 一个进程的多个线程使用的是同一个地址空间
# 实现下载线程
from threading import Thread
from queue import Queue
 
 
class DownloadThread ( Thread ) :
 
     def __init__ ( self , sid , queue ) :
         Thread . __init__ ( self )
         self . sid = sid
         self . url = 'http://table.finance.yahoo.com/table.csv?s=%s.sz'
         self . url %= str ( sid ) . rjust ( 6 , '0' )
         self . queue = queue
 
     @ staticmethod
     def download ( url ) :
         response = requests . get ( url , timeout = 3 )
         if response . ok :
             return ( StringIO ( str ( response . content ) ) )
         # 返回一个支持文件操作的内存对象
 
     def run ( self ) :
         print ( 'Downloading  ... (%d)' % self . sid )
         # 1下载
         data = self . download ( self . url )
         # 2 将数据传给转换线程 sid, data
         # 加锁安全
         self . queue . put ( ( self . sid , data ) )
 
 
class ConvertThread ( Thread ) :
     def __init__ ( self , queue ) :
         Thread . __init__ ( self )
         self . queue = queue
     def csvToXml ( self , scsv , fxml ) :
         reader = csv . reader ( scsv )
         headers = next ( reader )
         headers = map ( lambda h : h . replace ( ' ' , '' ) , headers )
         root = Element ( 'Data' )
         for row in reader :
             eRow = Element ( 'Row' )
             root . append ( eRow )
         for tag , text in zip ( headers , row ) :
             e = Element ( tag )
             e . text = text
             eRow . append ( e )
             et = ElementTree ( root )
             et . write ( fxml )
 
     def run ( self ) :
         while True :
             sid , data = self . queue . get ( )
             print ( 'Converting to XML ... (%d)' % sid )
             if sid == - 1 :
                 break
         if data :
             fname = str ( sid ) . rjust ( 6 , '0' ) + '.xml'
 
             with open ( fname , 'wb' ) as wf :
                 self . csvToXml ( data , wf )
 
 
if __name__ == '__main__' :
     q = Queue ( )
     dThreads = [ DownloadThread ( i , q ) for i in range ( 1 , 11 ) ]
     cThreads = ConvertThread ( q )
     for t in dThreads :
         t . start ( )
     cThreads . start ( )
     for t in dThreads :
         t . join ( )
     # http://blog.youkuaiyun.com/u013679490/article/details/54767220
     q . put ( ( - 1 , None ) )



  • zeropython 微信公众号 5868037 QQ号 5868037@qq.com QQ邮箱
### Pythonthreading.Thread 的工作原理 在 Python 中,`threading.Thread` 是用于实现多线程编程的核心类[^1]。它通过封装底层的线程操作(如创建、启动和管理线程),为开发者提供了一个高层次的接口。以下是关于 `threading.Thread` 的工作原理及其多线程实现机制的详细说明: #### 1. 线程的创建与启动 当调用 `threading.Thread(target=func, args=())` 创建一个线程对象时,实际上并没有立即启动线程。只有当调用 `.start()` 方法时,Python 才会调用 CPython 底层的线程库来创建并启动新线程[^2]。在此之后,目标函数 `func` 将会在新的线程中执行。 #### 2. GIL(全局解释器锁)的影响 尽管 Python 提供了多线程支持,但由于存在 GIL(Global Interpreter Lock),同一时刻只有一个线程能够执行 Python 字节码[^3]。因此,在 CPU 密集型任务中,多线程并不能有效提升性能。然而,在 I/O 密集型任务中,GIL 会被释放以允许其他线程运行,从而提高并发性。 #### 3. 线程同步与通信 为了防止多个线程同时访问共享资源导致数据不一致,`threading` 模块提供了多种同步工具,例如锁(Lock)、事件(Event)、条件变量(Condition)等[^4]。这些工具可以确保线程之间的安全协作。 #### 4. 线程生命周期管理 每个线程都有其生命周期,从创建到启动,再到运行和终止。`threading.Thread` 提供了诸如 `.join()` 和 `.is_alive()` 等方法来监控和管理线程状态[^5]。`.join()` 方法可以让主线程等待子线程完成后再继续执行。 #### 示例代码 以下是一个简单的多线程示例,展示了如何使用 `threading.Thread` 来执行并发任务: ```python import threading import time def worker(name, delay): print(f"Thread {name} starting") time.sleep(delay) print(f"Thread {name} finishing") # 创建线程 thread1 = threading.Thread(target=worker, args=("A", 2)) thread2 = threading.Thread(target=worker, args=("B", 4)) # 启动线程 thread1.start() thread2.start() # 等待线程完成 thread1.join() thread2.join() print("All threads finished") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值