【实用】Python中的并发编程及应用
随着计算机处理器性能的提高,我们的代码执行速度也得到了极大的提升。但是,随着数据量的不断增加以及业务的不断扩展,传统的单线程编程方式已经不能满足我们的需求。因此,我们需要一种更为高效的编程方式,那就是并发编程。
Python 是一门十分适合并发编程的语言。它提供了丰富的内置库和第三方库,可以让程序员轻松地实现并发编程。在本文中,我们将介绍 Python 中的并发编程以及如何应用它们。
一、并发编程的概念
并发编程是指在程序中同时执行多个任务的编程方式。举个例子,假设我们需要下载多个文件。传统的单线程编程方式可能需要依次下载每个文件,这样会大大降低程序的效率。而使用并发编程,我们可以同时下载多个文件,极大提高程序的效率。
但是并发编程的实现可以有多种方式,比如多线程、多进程、协程等。在 Python 中,除了使用多线程和多进程之外,还可以使用协程来实现并发编程。
二、多线程
多线程是一种常用的并发编程方式,可以让程序同时执行多个任务,从而提高程序的效率。在 Python 中实现多线程需要使用 threading 库。
下面是一个简单的例子:
```python
import threading
def print_numbers():
for i in range(10):
print(i)
def print_letters():
for i in range(10):
print(chr(ord('a')+i))
if __name__ == '__main__':
t1 = threading.Thread(target=print_numbers)
t2 = threading.Thread(target=print_letters)
t1.start()
t2.start()
```
在这个例子中,我们定义了两个函数分别用来打印数字和字母。然后使用 threading.Thread() 函数创建了两个线程,并将这两个函数作为参数传递进去。最后调用 start() 方法来启动线程。
需要注意的是,当我们运行这个程序的时候,可能会出现数字和字母打印混乱的情况。这是因为多线程是同时执行的,它们之间的执行顺序是无法保证的。
三、多进程
多进程也是一种常用的并发编程方式,可以让程序同时执行多个任务,从而提高程序的效率。在 Python 中实现多进程需要使用 multiprocessing 库。
下面是一个简单的例子:
```python
import multiprocessing
def print_numbers():
for i in range(10):
print(i)
def print_letters():
for i in range(10):
print(chr(ord('a')+i))
if __name__ == '__main__':
p1 = multiprocessing.Process(target=print_numbers)
p2 = multiprocessing.Process(target=print_letters)
p1.start()
p2.start()
```
在这个例子中,我们同样定义了两个函数分别用来打印数字和字母。然后使用 multiprocessing.Process() 函数创建了两个进程,并将这两个函数作为参数传递进去。最后调用 start() 方法来启动进程。
需要注意的是,多进程需要考虑到进程间通信的问题,比如使用 Queue 或者 Pipe 等方式来实现进程间通信。
四、协程
协程是一种轻量级的并发编程方式,可以轻松地实现大量的并发任务。在 Python 中实现协程需要使用 asyncio 库。
下面是一个简单的例子:
```python
import asyncio
async def print_numbers():
for i in range(10):
print(i)
await asyncio.sleep(0.1)
async def print_letters():
for i in range(10):
print(chr(ord('a')+i))
await asyncio.sleep(0.1)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(print_numbers(), print_letters()))
```
在这个例子中,我们定义了两个协程函数分别用来打印数字和字母。然后使用 asyncio.gather() 函数来将这两个协程函数一起运行。
需要注意的是,协程需要使用 async 和 await 关键字来定义和调用协程函数。
五、应用实例
下面我们来介绍一下如何使用并发编程来实现常见的应用场景。
1. 爬虫
爬虫是一种常见的并发场景,可以使用多线程或者协程来提高爬虫的效率。下面是一个使用多线程实现的简单爬虫:
```python
import requests
import threading
from queue import Queue
url_list = [
'http://www.baidu.com',
'http://www.qq.com',
'http://www.sina.com',
'http://www.taobao.com',
]
def get_url(q):
while not q.empty():
url = q.get()
r = requests.get(url)
print(url, len(r.text))
def main():
q = Queue()
for url in url_list:
q.put(url)
thread_list = []
for i in range(5):
t = threading.Thread(target=get_url, args=(q,))
t.start()
thread_list.append(t)
for t in thread_list:
t.join()
if __name__ == '__main__':
main()
```
在这个例子中,我们定义了一个函数 get_url() 来获取网页内容。然后使用 Queue 来存储需要爬取的网址。使用多线程来同时访问多个网址。需要注意的是,在实际开发中需要添加一些限制条件来防止被封 IP。
2. 数据处理
数据处理是一种常见的并发场景,可以使用多进程或者协程来提高数据处理的效率。下面是一个使用多进程实现的简单数据处理程序:
```python
import multiprocessing
data_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def square(data):
return data*data
if __name__ == '__main__':
pool = multiprocessing.Pool(processes=4)
results = []
for data in data_list:
result = pool.apply_async(square, args=(data,))
results.append(result)
pool.close()
pool.join()
for result in results:
print(result.get())
```
在这个例子中,我们定义了一个函数 square() 来计算数据的平方。然后使用 multiprocessing.Pool() 函数来创建进程池。将数据进行分组,并且使用 apply_async() 方法来异步计算。最后使用 get() 方法获取数据计算结果。
需要注意的是,在实际开发中需要考虑到进程间通信和数据分布的问题。
3. 实时数据处理
实时数据处理是一种常见的并发场景,可以使用协程来提高实时数据处理的效率。下面是一个使用协程实现实时数据处理程序:
```python
import asyncio
async def read_data():
while True:
data = await read_sensor()
await process_data(data)
async def read_sensor():
# 从传感器读取数据
pass
async def process_data(data):
# 处理数据
pass
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(read_data())
```
在这个例子中,我们定义了两个协程函数 read_sensor() 和 process_data(),分别用来读取传感器数据和处理数据。使用 asyncio.get_event_loop() 函数来创建事件循环,然后使用 run_until_complete() 方法来运行协程函数 read_data()。
需要注意的是,在实际开发中协程的执行顺序是无法保证的,这需要根据具体的业务需求进行调整。
六、总结
并发编程是一种提高程序效率的重要方式。在 Python 中,可以使用多线程、多进程、协程等方式实现并发编程。需要根据不同的业务需求选择合适的并发编程方式。同时,需要注意到并发编程也会带来一些问题,如竞态条件、锁问题等,需要谨慎处理。