当前位置: 首页 > news >正文

MetaGPT中的教程助手:TutorialAssistant

1. 提示词

COMMON_PROMPT = """
You are now a seasoned technical professional in the field of the internet. 
We need you to write a technical tutorial with the topic "{topic}".
"""DIRECTORY_PROMPT = (COMMON_PROMPT+ """
Please provide the specific table of contents for this tutorial, strictly following the following requirements:
1. The output must be strictly in the specified language, {language}.
2. Answer strictly in the dictionary format like {{"title": "xxx", "directory": [{{"dir 1": ["sub dir 1", "sub dir 2"]}}, {{"dir 2": ["sub dir 3", "sub dir 4"]}}]}}.
3. The directory should be as specific and sufficient as possible, with a primary and secondary directory.The secondary directory is in the array.
4. Do not have extra spaces or line breaks.
5. Each directory title has practical significance.
"""
)
CONTENT_PROMPT = (COMMON_PROMPT+ """
Now I will give you the module directory titles for the topic. 
Please output the detailed principle content of this title in detail. 
If there are code examples, please provide them according to standard code specifications. 
Without a code example, it is not necessary.The module directory titles for the topic is as follows:
{directory}Strictly limit output according to the following requirements:
1. Follow the Markdown syntax format for layout.
2. If there are code examples, they must follow standard syntax specifications, have document annotations, and be displayed in code blocks.
3. The output must be strictly in the specified language, {language}.
4. Do not have redundant output, including concluding remarks.
5. Strict requirement not to output the topic "{topic}".
"""
)

2. 两个动作: 写文档大纲 (WriteDirectory) 和文档内容 (WriteContent)

from typing import Dictfrom metagpt.actions import Action
from metagpt.utils.common import OutputParserclass WriteDirectory(Action):"""Action class for writing tutorial directories.Args:name: The name of the action.language: The language to output, default is "Chinese"."""name: str = "WriteDirectory"language: str = "Chinese"async def run(self, topic: str, *args, **kwargs) -> Dict:"""Execute the action to generate a tutorial directory according to the topic.Args:topic: The tutorial topic.Returns:the tutorial directory information, including {"title": "xxx", "directory": [{"dir 1": ["sub dir 1", "sub dir 2"]}]}."""prompt = DIRECTORY_PROMPT.format(topic=topic, language=self.language)resp = await self._aask(prompt=prompt)return OutputParser.extract_struct(resp, dict)class WriteContent(Action):"""Action class for writing tutorial content.Args:name: The name of the action.directory: The content to write.language: The language to output, default is "Chinese"."""name: str = "WriteContent"directory: dict = dict()language: str = "Chinese"async def run(self, topic: str, *args, **kwargs) -> str:"""Execute the action to write document content according to the directory and topic.Args:topic: The tutorial topic.Returns:The written tutorial content."""prompt = CONTENT_PROMPT.format(topic=topic, language=self.language, directory=self.directory)return await self._aask(prompt=prompt)

3. 教程助手定义

具体逻辑:第一步写文档目录,第二步,根据文档目录写每一章的内容,第三步,将内容写入markdown文件中

from datetime import datetime
from typing import Dict
from metagpt.const import get_metagpt_root
from metagpt.logs import logger
from metagpt.roles.role import Role
from metagpt.schema import Message
from metagpt.utils.file import FileTUTORIAL_PATH = get_metagpt_root()/"data"/"tutorial_docx"class TutorialAssistant(Role):"""Tutorial assistant, input one sentence to generate a tutorial document in markup format.Args:name: The name of the role.profile: The role profile description.goal: The goal of the role.constraints: Constraints or requirements for the role.language: The language in which the tutorial documents will be generated."""name: str = "Stitch"profile: str = "Tutorial Assistant"goal: str = "Generate tutorial documents"constraints: str = "Strictly follow Markdown's syntax, with neat and standardized layout"language: str = "Chinese"topic: str = ""main_title: str = ""total_content: str = ""def __init__(self, **kwargs):super().__init__(**kwargs)self.set_actions([WriteDirectory(language=self.language)])self._set_react_mode(react_mode="by_order")async def _handle_directory(self, titles: Dict) -> Message:"""Handle the directories for the tutorial document.Args:titles: A dictionary containing the titles and directory structure,such as {"title": "xxx", "directory": [{"dir 1": ["sub dir 1", "sub dir 2"]}]}Returns:A message containing information about the directory."""self.main_title = titles.get("title")directory = f"{self.main_title}\n"self.total_content += f"# {self.main_title}"actions = list(self.actions)for first_dir in titles.get("directory"):actions.append(WriteContent(language=self.language, directory=first_dir))key = list(first_dir.keys())[0]directory += f"- {key}\n"for second_dir in first_dir[key]:directory += f"  - {second_dir}\n"self.set_actions(actions)self.rc.max_react_loop = len(self.actions)return Message()async def _act(self) -> Message:"""Perform an action as determined by the role.Returns:A message containing the result of the action."""todo = self.rc.todoif type(todo) is WriteDirectory:msg = self.rc.memory.get(k=1)[0]self.topic = msg.contentresp = await todo.run(topic=self.topic)logger.info(resp)return await self._handle_directory(resp)resp = await todo.run(topic=self.topic)logger.info(resp)if self.total_content != "":self.total_content += "\n\n\n"self.total_content += respreturn Message(content=resp, role=self.profile)async def react(self) -> Message:msg = await super().react()root_path = TUTORIAL_PATH / datetime.now().strftime("%Y-%m-%d_%H-%M-%S")await File.write(root_path, f"{self.main_title}.md", self.total_content.encode("utf-8"))msg.content = str(root_path / f"{self.main_title}.md")return msg
2024-12-12 15:39:46.005 | INFO     | metagpt.const:get_metagpt_package_root:21 - Package root set to d:\llm\metagpt

4. 示例

async def main():topic = "Write a tutorial about python asyncio"role = TutorialAssistant(language="Chinese")await role.run(topic)await main()

输出:

{
"title": "Python Asyncio 异步编程教程",
"directory": [{"一、异步编程基础": ["1.1 异步编程概念","1.2 Python中的异步历史","1.3 异步编程的优势"]},{"二、Asyncio入门": ["2.1 安装与配置","2.2 Event Loop事件循环","2.3 coroutine协程","2.4 Future对象","2.5 使用async和await"]},{"三、Asyncio高级应用": ["3.1 并发执行与同步","3.2 异步网络请求","3.3 异步文件操作","3.4 异步数据库操作","3.5 异步队列"]},{"四、常见问题与解决方案": ["4.1 协程间通信","4.2 异步异常处理","4.3 性能优化","4.4 兼容性问题"]},{"五、实战案例": ["5.1 异步爬虫","5.2 异步Web服务","5.3 异步数据处理"]},{"六、附录": ["6.1 常用库与资源","6.2 最佳实践","6.3 进一步学习"]}
]
}2024-12-12 15:39:57.769 | WARNING  | metagpt.utils.cost_manager:update_cost:49 - Model GLM-4 not found in TOKEN_COSTS.
2024-12-12 15:39:57.770 | INFO     | __main__:_act:72 - {'title': 'Python Asyncio 异步编程教程', 'directory': [{'一、异步编程基础': ['1.1 异步编程概念', '1.2 Python中的异步历史', '1.3 异步编程的优势']}, {'二、Asyncio入门': ['2.1 安装与配置', '2.2 Event Loop事件循环', '2.3 coroutine协程', '2.4 Future对象', '2.5 使用async和await']}, {'三、Asyncio高级应用': ['3.1 并发执行与同步', '3.2 异步网络请求', '3.3 异步文件操作', '3.4 异步数据库操作', '3.5 异步队列']}, {'四、常见问题与解决方案': ['4.1 协程间通信', '4.2 异步异常处理', '4.3 性能优化', '4.4 兼容性问题']}, {'五、实战案例': ['5.1 异步爬虫', '5.2 异步Web服务', '5.3 异步数据处理']}, {'六、附录': ['6.1 常用库与资源', '6.2 最佳实践', '6.3 进一步学习']}]}# 一、异步编程基础## 1.1 异步编程概念异步编程是一种编程范式,允许程序在等待某些操作完成(如I/O操作)时继续执行其他任务。与传统的同步编程不同,同步编程在等待操作完成时会阻塞当前任务的执行。异步编程可以提高程序的效率和响应性。## 1.2 Python中的异步历史Python的异步编程经历了几个阶段的发展:- Python 2.x时代:主要通过`threading`和`multiprocessing`模块实现并发。
- Python 3.0至3.3:引入了`yield`关键字和`generators`,可以通过生成器实现简单的协同程序。
- Python 3.4:引入了`asyncio`库,提供了编写单线程并发代码的框架。
- Python 3.5:引入了`async`和`await`关键字,使得异步编程更加直观和易于编写。## 1.3 异步编程的优势异步编程具有以下优势:1. 提高I/O密集型应用的性能:在等待I/O操作完成时,CPU可以切换到其他任务,从而提高资源利用率。
2. 更好的资源利用:异步编程允许使用单线程管理多个并发任务,减少了线程或进程的开销。
3. 提升用户体验:在Web应用和用户界面中,异步编程可以避免因长时间操作导致的界面冻结。以下是一个简单的使用`asyncio`的例子:```python
import asyncioasync def hello_world():print("Hello")await asyncio.sleep(1)  # 模拟I/O操作print("World")# 运行异步函数
asyncio.run(hello_world())
```请注意,上述代码应在Python 3.7及以上版本运行,因为`asyncio.run()`函数是在Python 3.7中引入的。在之前的版本中,需要使用`asyncio.get_event_loop().run_until_complete(hello_world())`来运行异步函数2024-12-12 15:40:15.460 | WARNING  | metagpt.utils.cost_manager:update_cost:49 - Model GLM-4 not found in TOKEN_COSTS.
2024-12-12 15:40:15.462 | INFO     | __main__:_act:75 - # 一、异步编程基础## 1.1 异步编程概念异步编程是一种编程范式,允许程序在等待某些操作完成(如I/O操作)时继续执行其他任务。与传统的同步编程不同,同步编程在等待操作完成时会阻塞当前任务的执行。异步编程可以提高程序的效率和响应性。## 1.2 Python中的异步历史Python的异步编程经历了几个阶段的发展:- Python 2.x时代:主要通过`threading`和`multiprocessing`模块实现并发。
- Python 3.0至3.3:引入了`yield`关键字和`generators`,可以通过生成器实现简单的协同程序。
- Python 3.4:引入了`asyncio`库,提供了编写单线程并发代码的框架。
- Python 3.5:引入了`async`和`await`关键字,使得异步编程更加直观和易于编写。## 1.3 异步编程的优势异步编程具有以下优势:1. 提高I/O密集型应用的性能:在等待I/O操作完成时,CPU可以切换到其他任务,从而提高资源利用率。
2. 更好的资源利用:异步编程允许使用单线程管理多个并发任务,减少了线程或进程的开销。
3. 提升用户体验:在Web应用和用户界面中,异步编程可以避免因长时间操作导致的界面冻结。以下是一个简单的使用`asyncio`的例子:```python
import asyncioasync def hello_world():print("Hello")await asyncio.sleep(1)  # 模拟I/O操作print("World")# 运行异步函数
asyncio.run(hello_world())
```请注意,上述代码应在Python 3.7及以上版本运行,因为`asyncio.run()`函数是在Python 3.7中引入的。在之前的版本中,需要使用`asyncio.get_event_loop().run_until_complete(hello_world())`来运行异步函数。。
# 二、Asyncio入门## 2.1 安装与配置Asyncio 是 Python 的一个库,用于编写单线程并发代码,通过异步/等待语法。要在 Python 中使用 asyncio,你需要 Python 3.5 或更高版本。### 安装Asyncio 随 Python 3.4+ 一起安装,无需额外安装。### 配置无需特别的配置,直接在 Python 脚本中导入即可使用。```python
import asyncio
```## 2.2 Event Loop事件循环事件循环是 asyncio 程序的核心,它用来调度和执行任务。```python
# 示例:创建事件循环
loop = asyncio.get_event_loop()
try:loop.run_forever()
finally:loop.close()
```## 2.3 coroutine协程协程是使用 `async def` 定义的函数,它是异步编程的核心。```python
# 示例:定义协程
async def main():print('Hello')await asyncio.sleep(1)print('World')# 运行协程
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
```## 2.4 Future对象Future 对象表示尚未完成的计算,它用来与异步执行的结果进行交互。```python
# 示例:创建 Future 对象
async def main():# 获取当前事件循环loop = asyncio.get_event_loop()# 创建一个 Future 对象future = loop.create_future()# 模拟异步操作,并在一段时间后设置结果async def set_future():await asyncio.sleep(1)future.set_result('Future is done!')# 启动任务loop.create_task(set_future())# 等待 Future 完成result = await futureprint(result)loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
```## 2.5 使用async和await`async` 和 `await` 关键字用于编写异步代码。```python
# 示例:使用 async 和 await
async def say_after(delay, what):await asyncio.sleep(delay)print(what)async def main():print(f"started at {time.strftime('%X')}")await say_after(1, 'hello')await say_after(2, 'world')print(f"finished at {time.strftime('%X')}")asyncio.run(main())
```请注意,上面的示例中使用了 `asyncio.run(main())`,这是 Python 3.7+ 推荐的运行协程的方式,代替了手动获取事件循环和关闭事件循环的做法。`asyncio.run()` 应该只被调用一次,通常在主程序入口处。2024-12-12 15:40:36.272 | WARNING  | metagpt.utils.cost_manager:update_cost:49 - Model GLM-4 not found in TOKEN_COSTS.
2024-12-12 15:40:36.274 | INFO     | __main__:_act:75 - # 二、Asyncio入门## 2.1 安装与配置Asyncio 是 Python 的一个库,用于编写单线程并发代码,通过异步/等待语法。要在 Python 中使用 asyncio,你需要 Python 3.5 或更高版本。### 安装Asyncio 随 Python 3.4+ 一起安装,无需额外安装。### 配置无需特别的配置,直接在 Python 脚本中导入即可使用。```python
import asyncio
```## 2.2 Event Loop事件循环事件循环是 asyncio 程序的核心,它用来调度和执行任务。```python
# 示例:创建事件循环
loop = asyncio.get_event_loop()
try:loop.run_forever()
finally:loop.close()
```## 2.3 coroutine协程协程是使用 `async def` 定义的函数,它是异步编程的核心。```python
# 示例:定义协程
async def main():print('Hello')await asyncio.sleep(1)print('World')# 运行协程
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
```## 2.4 Future对象Future 对象表示尚未完成的计算,它用来与异步执行的结果进行交互。```python
# 示例:创建 Future 对象
async def main():# 获取当前事件循环loop = asyncio.get_event_loop()# 创建一个 Future 对象future = loop.create_future()# 模拟异步操作,并在一段时间后设置结果async def set_future():await asyncio.sleep(1)future.set_result('Future is done!')# 启动任务loop.create_task(set_future())# 等待 Future 完成result = await futureprint(result)loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
```## 2.5 使用async和await`async` 和 `await` 关键字用于编写异步代码。```python
# 示例:使用 async 和 await
async def say_after(delay, what):await asyncio.sleep(delay)print(what)async def main():print(f"started at {time.strftime('%X')}")await say_after(1, 'hello')await say_after(2, 'world')print(f"finished at {time.strftime('%X')}")asyncio.run(main())
```请注意,上面的示例中使用了 `asyncio.run(main())`,这是 Python 3.7+ 推荐的运行协程的方式,代替了手动获取事件循环和关闭事件循环的做法。`asyncio.run()` 应该只被调用一次,通常在主程序入口处。# 三、Asyncio高级应用## 3.1 并发执行与同步`asyncio` 是 Python 的一个异步I/O框架,用于编写单线程并发代码,通过异步/等待语法。### 并发执行`asyncio` 允许我们并发地运行多个协程。以下是一个简单的并发执行示例:```python
import asyncioasync def say_after(delay, what):await asyncio.sleep(delay)print(what)async def main():print(f"started at {time.strftime('%X')}")# 创建两个协程对象,不立即运行coroutine1 = say_after(1, 'hello')coroutine2 = say_after(2, 'world')# 等待两个协程并发执行await asyncio.gather(coroutine1, coroutine2)print(f"finished at {time.strftime('%X')}")# 运行主协程
asyncio.run(main())
```### 同步在并发编程中,同步是确保多个任务按预期执行的机制。`asyncio` 提供了 `asyncio.Lock()` 和 `asyncio.Event()` 等同步原语。以下是一个使用 `asyncio.Lock()` 的示例:```python
import asyncioasync def worker(lock, worker_id):print(f"Worker {worker_id} waiting for the lock")async with lock:print(f"Worker {worker_id} has the lock")await asyncio.sleep(1)print(f"Worker {worker_id} released the lock")async def main():# 创建一个锁lock = asyncio.Lock()# 创建并运行三个工作协程tasks = [asyncio.create_task(worker(lock, i)) for i in range(3)]await asyncio.gather(*tasks)# 运行主协程
asyncio.run(main())
```## 3.2 异步网络请求`aiohttp` 是一个支持 `asyncio` 的异步HTTP网络库。```python
import aiohttp
import asyncioasync def fetch(session, url):async with session.get(url) as response:return await response.text()async def main():async with aiohttp.ClientSession() as session:html = await fetch(session, 'http://python.org')print(html)# 运行主协程
asyncio.run(main())
```## 3.3 异步文件操作`asyncio` 允许你以异步方式执行文件操作。```python
import asyncio
import aiofilesasync def write_to_file(filename, content):async with aiofiles.open(filename, 'w') as f:await f.write(content)async def main():await write_to_file('example.txt', 'Hello, world!')# 运行主协程
asyncio.run(main())
```## 3.4 异步数据库操作对于数据库操作,可以使用像 `aiomysql` 或 `aiopg` 这样的异步驱动。以下是使用 `aiomysql` 的简单示例:```python
import asyncio
import aiomysqlasync def query_db(loop, dbname, user, password):async with aiomysql.create_pool(host='127.0.0.1', port=3306,user=user, password=password,db=dbname, loop=loop) as pool:async with pool.acquire() as conn:async with conn.cursor() as cur:await cur.execute("SELECT 1")result = await cur.fetchone()print(result)loop = asyncio.get_event_loop()
loop.run_until_complete(query_db(loop, 'test', 'user', 'password'))
```## 3.5 异步队列`asyncio` 提供了 `asyncio.Queue`,这是一个异步的先进先出(FIFO)队列。```python
import asyncioasync def worker(q):while True:item = await q.get()print(f'Worker got item: {item}')# 模拟处理项目await asyncio.sleep(1)q.task_done()async def main():q = asyncio.Queue(maxsize=3)# 启动三个工作协程tasks = []for i in range(3):task = asyncio.create_task(worker(q))tasks.append(task)# 生产项目for item in range(10):await q.put(item)# 等待队列清空await q.join()# 取消工作协程for task in tasks:task.cancel()await asyncio.gather(*tasks, return_exceptions=True)# 运行主协程
asyncio.run(main())
```请注意,以上示例代码遵循了代码规范,并包含了必要的注释,以方便理解。2024-12-12 15:41:09.514 | WARNING  | metagpt.utils.cost_manager:update_cost:49 - Model GLM-4 not found in TOKEN_COSTS.
2024-12-12 15:41:09.515 | INFO     | __main__:_act:75 - # 三、Asyncio高级应用## 3.1 并发执行与同步`asyncio` 是 Python 的一个异步I/O框架,用于编写单线程并发代码,通过异步/等待语法。### 并发执行`asyncio` 允许我们并发地运行多个协程。以下是一个简单的并发执行示例:```python
import asyncioasync def say_after(delay, what):await asyncio.sleep(delay)print(what)async def main():print(f"started at {time.strftime('%X')}")# 创建两个协程对象,不立即运行coroutine1 = say_after(1, 'hello')coroutine2 = say_after(2, 'world')# 等待两个协程并发执行await asyncio.gather(coroutine1, coroutine2)print(f"finished at {time.strftime('%X')}")# 运行主协程
asyncio.run(main())
```### 同步在并发编程中,同步是确保多个任务按预期执行的机制。`asyncio` 提供了 `asyncio.Lock()` 和 `asyncio.Event()` 等同步原语。以下是一个使用 `asyncio.Lock()` 的示例:```python
import asyncioasync def worker(lock, worker_id):print(f"Worker {worker_id} waiting for the lock")async with lock:print(f"Worker {worker_id} has the lock")await asyncio.sleep(1)print(f"Worker {worker_id} released the lock")async def main():# 创建一个锁lock = asyncio.Lock()# 创建并运行三个工作协程tasks = [asyncio.create_task(worker(lock, i)) for i in range(3)]await asyncio.gather(*tasks)# 运行主协程
asyncio.run(main())
```## 3.2 异步网络请求`aiohttp` 是一个支持 `asyncio` 的异步HTTP网络库。```python
import aiohttp
import asyncioasync def fetch(session, url):async with session.get(url) as response:return await response.text()async def main():async with aiohttp.ClientSession() as session:html = await fetch(session, 'http://python.org')print(html)# 运行主协程
asyncio.run(main())
```## 3.3 异步文件操作`asyncio` 允许你以异步方式执行文件操作。```python
import asyncio
import aiofilesasync def write_to_file(filename, content):async with aiofiles.open(filename, 'w') as f:await f.write(content)async def main():await write_to_file('example.txt', 'Hello, world!')# 运行主协程
asyncio.run(main())
```## 3.4 异步数据库操作对于数据库操作,可以使用像 `aiomysql` 或 `aiopg` 这样的异步驱动。以下是使用 `aiomysql` 的简单示例:```python
import asyncio
import aiomysqlasync def query_db(loop, dbname, user, password):async with aiomysql.create_pool(host='127.0.0.1', port=3306,user=user, password=password,db=dbname, loop=loop) as pool:async with pool.acquire() as conn:async with conn.cursor() as cur:await cur.execute("SELECT 1")result = await cur.fetchone()print(result)loop = asyncio.get_event_loop()
loop.run_until_complete(query_db(loop, 'test', 'user', 'password'))
```## 3.5 异步队列`asyncio` 提供了 `asyncio.Queue`,这是一个异步的先进先出(FIFO)队列。```python
import asyncioasync def worker(q):while True:item = await q.get()print(f'Worker got item: {item}')# 模拟处理项目await asyncio.sleep(1)q.task_done()async def main():q = asyncio.Queue(maxsize=3)# 启动三个工作协程tasks = []for i in range(3):task = asyncio.create_task(worker(q))tasks.append(task)# 生产项目for item in range(10):await q.put(item)# 等待队列清空await q.join()# 取消工作协程for task in tasks:task.cancel()await asyncio.gather(*tasks, return_exceptions=True)# 运行主协程
asyncio.run(main())
```请注意,以上示例代码遵循了代码规范,并包含了必要的注释,以方便理解。# 四、常见问题与解决方案## 4.1 协程间通信在Python的`asyncio`中,协程之间的通信通常使用`asyncio.Queue`或者`asyncio.Event`来实现。### 示例:使用`asyncio.Queue````python
import asyncioasync def producer(queue):for i in range(5):print(f"Producing item {i}")await queue.put(i)await queue.put(None)  # 用来标记生产结束async def consumer(queue):while True:item = await queue.get()if item is None:breakprint(f"Consuming item {item}")await asyncio.sleep(1)  # 模拟消费时间queue.task_done()queue = asyncio.Queue()
producer_coro = producer(queue)
consumer_coro = consumer(queue)loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(producer_coro, consumer_coro))
loop.close()
```## 4.2 异步异常处理在异步编程中,异常处理非常重要。可以使用`try-except`块来捕获和处理异常。### 示例:异步异常处理```python
import asyncioasync def async_function_with_error():raise ValueError("An error occurred")async def main():try:await async_function_with_error()except ValueError as e:print(f"Caught an exception: {e}")loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
```## 4.3 性能优化性能优化通常涉及减少协程之间的等待时间,以及减少不必要的上下文切换。- 使用`asyncio.gather`来并发运行多个协程。
- 使用`await`关键字仅在你确实需要等待某个操作完成时。### 示例:并发运行多个协程```python
import asyncioasync def fast_function():await asyncio.sleep(1)async def main():await asyncio.gather(fast_function(),fast_function(),fast_function())loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
```## 4.4 兼容性问题由于`asyncio`是Python 3.4+的一部分,如果你需要支持更早的Python版本,可能会遇到兼容性问题。- 使用`asyncio`之前,检查Python版本。
- 使用`pip`安装`asyncio`的第三方包,如`aiolib`,来支持旧版本的Python。确保你的代码在支持的版本范围内运行良好,并且遵循最佳实践来减少兼容性问题。---请注意,以上内容遵循了Markdown的语法规范,并提供了相应的代码示例。代码示例遵循了标准的Python代码规范,并包含了必要的2024-12-12 15:41:28.223 | WARNING  | metagpt.utils.cost_manager:update_cost:49 - Model GLM-4 not found in TOKEN_COSTS.注释。2024-12-12 15:41:28.226 | INFO     | __main__:_act:75 - # 四、常见问题与解决方案## 4.1 协程间通信在Python的`asyncio`中,协程之间的通信通常使用`asyncio.Queue`或者`asyncio.Event`来实现。### 示例:使用`asyncio.Queue````python
import asyncioasync def producer(queue):for i in range(5):print(f"Producing item {i}")await queue.put(i)await queue.put(None)  # 用来标记生产结束async def consumer(queue):while True:item = await queue.get()if item is None:breakprint(f"Consuming item {item}")await asyncio.sleep(1)  # 模拟消费时间queue.task_done()queue = asyncio.Queue()
producer_coro = producer(queue)
consumer_coro = consumer(queue)loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(producer_coro, consumer_coro))
loop.close()
```## 4.2 异步异常处理在异步编程中,异常处理非常重要。可以使用`try-except`块来捕获和处理异常。### 示例:异步异常处理```python
import asyncioasync def async_function_with_error():raise ValueError("An error occurred")async def main():try:await async_function_with_error()except ValueError as e:print(f"Caught an exception: {e}")loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
```## 4.3 性能优化性能优化通常涉及减少协程之间的等待时间,以及减少不必要的上下文切换。- 使用`asyncio.gather`来并发运行多个协程。
- 使用`await`关键字仅在你确实需要等待某个操作完成时。### 示例:并发运行多个协程```python
import asyncioasync def fast_function():await asyncio.sleep(1)async def main():await asyncio.gather(fast_function(),fast_function(),fast_function())loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
```## 4.4 兼容性问题由于`asyncio`是Python 3.4+的一部分,如果你需要支持更早的Python版本,可能会遇到兼容性问题。- 使用`asyncio`之前,检查Python版本。
- 使用`pip`安装`asyncio`的第三方包,如`aiolib`,来支持旧版本的Python。确保你的代码在支持的版本范围内运行良好,并且遵循最佳实践来减少兼容性问题。---请注意,以上内容遵循了Markdown的语法规范,并提供了相应的代码示例。代码示例遵循了标准的Python代码规范,并包含了必要的注释。# 五、实战案例## 5.1 异步爬虫异步IO在爬虫领域有广泛的应用,因为它可以显著提高爬取效率,特别是在处理网络请求时。以下是一个使用`asyncio`和`aiohttp`的异步爬虫示例。```python
import asyncio
import aiohttpasync def fetch(session, url):async with session.get(url) as response:return await response.text()async def main():async with aiohttp.ClientSession() as session:url = 'http://example.com'html = await fetch(session, url)print(html)if __name__ == '__main__':asyncio.run(main())
```在这个示例中,`fetch` 函数是一个异步的HTTP请求处理函数,它使用了`aiohttp`库来异步获取网页内容。`main` 函数初始化了一个`aiohttp.ClientSession`,然后调用`fetch`函数,并打印出获取的HTML内容。## 5.2 异步Web服务`asyncio`也可以用于创建异步的Web服务。下面是一个使用`aiohttp`创建的简单异步Web服务示例。```python
from aiohttp import webasync def handle(request):name = request.match_info.get('name', "Anonymous")text = f"Hello, {name}!"return web.Response(text=text)app = web.Application()
app.add_routes([web.get('/', handle),web.get('/{name}', handle)
])web.run_app(app)
```在这个例子中,我们创建了一个简单的Web应用程序,它响应根URL和带名字的路径。`handle` 函数是一个异步处理函数,它根据URL路径中的名字返回响应。## 5.3 异步数据处理在数据处理任务中,如果任务可以并行处理,`asyncio`也能提供帮助。以下是一个使用`asyncio`进行异步文件读写的例子。```python
import asyncio
import aiofilesasync def write_data(file_path, data):async with aiofiles.open(file_path, 'w') as f:await f.write(data)async def read_data(file_path):async with aiofiles.open(file_path, 'r') as f:data = await f.read()print(data)async def main():file_path = 'example.txt'data_to_write = '异步文件写入示例'# 写入数据await write_data(file_path, data_to_write)# 读取数据await read_data(file_path)if __name__ == '__main__':asyncio.run(main())
```在这个例子中,`write_data` 函数异步地将数据写入文件,而`read_data` 函数从文件异步读取数据。通过这种方式,可以在处理I/O密集型任务时提高效率。2024-12-12 15:41:46.964 | WARNING  | metagpt.utils.cost_manager:update_cost:49 - Model GLM-4 not found in TOKEN_COSTS.
2024-12-12 15:41:46.965 | INFO     | __main__:_act:75 - # 五、实战案例## 5.1 异步爬虫异步IO在爬虫领域有广泛的应用,因为它可以显著提高爬取效率,特别是在处理网络请求时。以下是一个使用`asyncio`和`aiohttp`的异步爬虫示例。```python
import asyncio
import aiohttpasync def fetch(session, url):async with session.get(url) as response:return await response.text()async def main():async with aiohttp.ClientSession() as session:url = 'http://example.com'html = await fetch(session, url)print(html)if __name__ == '__main__':asyncio.run(main())
```在这个示例中,`fetch` 函数是一个异步的HTTP请求处理函数,它使用了`aiohttp`库来异步获取网页内容。`main` 函数初始化了一个`aiohttp.ClientSession`,然后调用`fetch`函数,并打印出获取的HTML内容。## 5.2 异步Web服务`asyncio`也可以用于创建异步的Web服务。下面是一个使用`aiohttp`创建的简单异步Web服务示例。```python
from aiohttp import webasync def handle(request):name = request.match_info.get('name', "Anonymous")text = f"Hello, {name}!"return web.Response(text=text)app = web.Application()
app.add_routes([web.get('/', handle),web.get('/{name}', handle)
])web.run_app(app)
```在这个例子中,我们创建了一个简单的Web应用程序,它响应根URL和带名字的路径。`handle` 函数是一个异步处理函数,它根据URL路径中的名字返回响应。## 5.3 异步数据处理在数据处理任务中,如果任务可以并行处理,`asyncio`也能提供帮助。以下是一个使用`asyncio`进行异步文件读写的例子。```python
import asyncio
import aiofilesasync def write_data(file_path, data):async with aiofiles.open(file_path, 'w') as f:await f.write(data)async def read_data(file_path):async with aiofiles.open(file_path, 'r') as f:data = await f.read()print(data)async def main():file_path = 'example.txt'data_to_write = '异步文件写入示例'# 写入数据await write_data(file_path, data_to_write)# 读取数据await read_data(file_path)if __name__ == '__main__':asyncio.run(main())
```在这个例子中,`write_data` 函数异步地将数据写入文件,而`read_data` 函数从文件异步读取数据。通过这种方式,可以在处理I/O密集型任务时提高效率。# 六、附录## 6.1 常用库与资源Python 的 `asyncio` 是一个用于编写并发代码的库,使用async/await语法。以下是一些常用的库和资源,可以帮助你更好地理解和应用 `asyncio`。### 常用库- `aiohttp`:用于异步HTTP网络请求。
- `aiomysql` / `aiopg`:用于异步操作MySQL和PostgreSQL数据库。
- `aioredis`:用于异步操作Redis。
- `aiofiles`:用于异步文件操作。### 资源- [官方文档](https://docs.python.org/3/library/asyncio.html):提供了最权威的 `asyncio` 使用指南。
- [Asyncio GitHub 仓库](https://github.com/python/asyncio):可以找到最新的信息和一些示例。## 6.2 最佳实践在使用 `asyncio` 进行编程时,以下是一些最佳实践:1. **避免阻塞操作**:确保你的异步函数不会进行阻塞操作,如长时间的计算或等待输入/输出。
2. **合理使用并发**:不要盲目地创建大量协程,合理地管理和调度它们可以避免资源浪费和提高效率。
3. **错误处理**:使用 `try-except` 块来处理可能出现的异常,确保程序的健壮性。### 代码示例```python
import asyncioasync def fetch_data(url):async with aiohttp.ClientSession() as session:async with session.get(url) as response:return await response.text()async def main():urls = ['http://example.com', 'http://example.org']tasks = [fetch_data(url) for url in urls]results = await asyncio.gather(*tasks)for result in results:print(result)if __name__ == '__main__':asyncio.run(main())
```## 6.3 进一步学习想要进一步学习 `asyncio`,以下是一些建议:- **理解事件循环**:深入了解 `asyncio` 的事件循环是如何工作的,这是 `asyncio` 的核心概念。
- **并发模型**:研究 `asyncio` 的并发模型,包括协程、任务和未来。
- **性能调优**:学习如何对基于 `asyncio` 的应用进行性能分析和调优。通过这些资源的帮助,你可以更深入地掌握 `asyncio`,并在实践中更有效地2024-12-12 15:42:04.027 | WARNING  | metagpt.utils.cost_manager:update_cost:49 - Model GLM-4 not found in TOKEN_COSTS.使用它。2024-12-12 15:42:04.030 | INFO     | __main__:_act:75 - # 六、附录## 6.1 常用库与资源Python 的 `asyncio` 是一个用于编写并发代码的库,使用async/await语法。以下是一些常用的库和资源,可以帮助你更好地理解和应用 `asyncio`。### 常用库- `aiohttp`:用于异步HTTP网络请求。
- `aiomysql` / `aiopg`:用于异步操作MySQL和PostgreSQL数据库。
- `aioredis`:用于异步操作Redis。
- `aiofiles`:用于异步文件操作。### 资源- [官方文档](https://docs.python.org/3/library/asyncio.html):提供了最权威的 `asyncio` 使用指南。
- [Asyncio GitHub 仓库](https://github.com/python/asyncio):可以找到最新的信息和一些示例。## 6.2 最佳实践在使用 `asyncio` 进行编程时,以下是一些最佳实践:1. **避免阻塞操作**:确保你的异步函数不会进行阻塞操作,如长时间的计算或等待输入/输出。
2. **合理使用并发**:不要盲目地创建大量协程,合理地管理和调度它们可以避免资源浪费和提高效率。
3. **错误处理**:使用 `try-except` 块来处理可能出现的异常,确保程序的健壮性。### 代码示例```python
import asyncioasync def fetch_data(url):async with aiohttp.ClientSession() as session:async with session.get(url) as response:return await response.text()async def main():urls = ['http://example.com', 'http://example.org']tasks = [fetch_data(url) for url in urls]results = await asyncio.gather(*tasks)for result in results:print(result)if __name__ == '__main__':asyncio.run(main())
```## 6.3 进一步学习想要进一步学习 `asyncio`,以下是一些建议:- **理解事件循环**:深入了解 `asyncio` 的事件循环是如何工作的,这是 `asyncio` 的核心概念。
- **并发模型**:研究 `asyncio` 的并发模型,包括协程、任务和未来。
- **性能调优**:学习如何对基于 `asyncio` 的应用进行性能分析和调优。通过这些资源的帮助,你可以更深入地掌握 `asyncio`,并在实践中更有效地使用它。

参考链接:https://github.com/geekan/MetaGPT
如果有任何问题,欢迎在评论区提问。

相关文章:

MetaGPT中的教程助手:TutorialAssistant

1. 提示词 COMMON_PROMPT """ You are now a seasoned technical professional in the field of the internet. We need you to write a technical tutorial with the topic "{topic}". """DIRECTORY_PROMPT (COMMON_PROMPT "…...

介绍一款docker ui 管理工具

http://vm01:18999/main.html 管理员登陆账号 jinghan/123456 ui启动命令所在文件夹目录 /work/docker/docker-ui 参考链接 DockerUI:一款功能强大的中文Docker可视化管理工具_docker ui-CSDN博客...

0022 基于SpringBoot的婚纱摄影线上预约系统的设计与实现

电子商城系统 1.项目描述2. 绪论2.1 研究背景2.2 目的及意义2.3 国内外研究现状 3.需求分析4.界面展示5.源码获取 1.项目描述 摘 要 本文旨在研究并开发一套基于Spring Boot框架的婚纱摄影线上预约系统,以满足现代婚纱摄影行业对高效、便捷、个性化服务的需求。该系…...

uni-app在image上绘制点位并回显

在 Uni-app 中绘制多边形可以通过使用 Canvas API 来实现。Uni-app 是一个使用 Vue.js 开发所有前端应用的框架,同时支持编译为 H5、小程序等多个平台。由于 Canvas 是 H5 和小程序中都支持的 API,所以通过 Canvas 绘制多边形是一个比较通用的方法。 1.…...

Comparator.comparing 排序注意

1. 对数字型字符串排序 List<String> values new ArrayList<>();values.add("10");values.add("6");values.add("20");values.add("30");values.add("50");//方法1 &#xff08;正确的排序方法&#xff09;//倒…...

PPO系列3 - PPO原理

On Policy: 采集数据的模型&#xff0c;和训练的模型&#xff0c;是同一个。缺点&#xff1a;慢&#xff0c;生成一批样本数据&#xff0c;训练一次&#xff0c;又要重新生成下一批。 Off Policy: 采集数据的模型&#xff0c;和训练的模型&#xff0c;不是同一个。有点&#xf…...

.idea

.idea/ 文件夹下的文件和目录主要用于存储 JetBrains IDE&#xff08;如 PyCharm、IntelliJ IDEA 等&#xff09;的项目配置。下面是一些常见文件和目录及其作用的详细介绍&#xff1a; 1. workspace.xml 用户界面布局&#xff1a;保存了IDE窗口布局&#xff0c;包括打开的文…...

单片机:实现呼吸灯(附带源码)

单片机实现呼吸灯详细解读 呼吸灯是一种常见的灯光效果&#xff0c;广泛应用于电子产品、汽车、家居照明等领域。其基本特性是通过逐渐增亮和减弱的方式&#xff0c;使得灯光呈现出“呼吸”的效果&#xff0c;给人一种平缓、舒适的视觉感受。在嵌入式系统中&#xff0c;呼吸灯…...

PostgreSQL数据库序列信息查询

PostgreSQL序列信息查询 说明&#xff1a; 在PostgreSQL数据库中序列和表都是序列的对象。 数据库中不应该存在孤儿序列&#xff0c;序列应该和表对应的字段绑定起来。绑定后删除表或表对应的字段后&#xff0c;序列会自动被删除。 创建测试表和序列 create table test_t(…...

【Linux】Nginx一个域名https一个地址配置多个项目【项目实战】

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;CSDN博客专家   &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01…...

Linux驱动开发(12):中断子系统–按键中断实验

本章我们以按键为例讲解在驱动程序中如何使用中断&#xff0c; 在学习本章之前建议先回顾一下关于中断相关的裸机部分相关章节&#xff0c; 这里主要介绍在驱动中如何使用中断&#xff0c;对于中断的概念及GIC中断控制器相关内容不再进行讲解。 本章配套源码和设备树插件位于“…...

代码随想录-算法训练营-番外(图论02:岛屿数量,岛屿的最大面积)

day02 图论part02 今日任务:岛屿数量,岛屿的最大面积 都是一个模子套出来的 https://programmercarl.com/kamacoder/0099.岛屿的数量深搜.html#思路往日任务: day01 图论part01 今日任务:图论理论基础/所有可到达的路径 代码随想录图论视频部分还没更新 https://programmercar…...

20 go语言(golang) - gin框架安装及使用(一)

一、简介 Gin是一个用Go语言编写的高性能Web框架&#xff0c;专注于构建快速、可靠的HTTP服务。它以其速度和简洁性而闻名&#xff0c;非常适合用于开发RESTful API。 高性能&#xff1a;Gin使用了httprouter进行路由管理&#xff0c;这是一个轻量级且非常快速的HTTP请求路由器…...

重生之我在学Vue--第3天 Vue 3 模板语法与指令

重生之我在学Vue–第3天 Vue 3 模板语法与指令 文章目录 重生之我在学Vue--第3天 Vue 3 模板语法与指令前言一、数据绑定1.1 单向绑定1.2 双向绑定 二、常用指令2.1 v-bind2.2 v-model2.3 v-if2.4 v-show2.5 v-for2.6 v-on 三、事件处理与表单绑定3.1 事件处理3.2 表单绑定 前言…...

电脑win11家庭版升级专业版和企业版相关事项

我的是零刻ser9&#xff0c;自带win11家庭版&#xff0c;但是我有远程操控需求&#xff0c;想用windows系统自带的远程连接功能&#xff0c;所以需要升级为专业版。然后在系统激活页面通过更改序列号方式&#xff0c;淘宝几块钱买了个序列号升级成功专业版了。但是&#xff0c;…...

docker 架构详解

Docker架构是基于客户端-服务器&#xff08;C/S&#xff09;模式的&#xff0c;包含多个关键组件&#xff0c;以确保容器化应用的高效构建、管理和运行。以下是对Docker架构的详细解析&#xff1a; Docker 架构概述 Docker 架构采用客户端-服务器&#xff08;C/S&#xff09;…...

tinyCam Pro 用于远程监控,控制和录制您的私人公共网络或IP摄像机

tinyCam Pro 是一款用于远程监控&#xff0c;控制和录制您的私人/公共网络或IP摄像机&#xff0c;视频编码器和具有500万次下载的CCTV摄像头的DVR。需使用3G/4G/WiFi连接和下载数据。 tinyCam Monitor Pro 可用于远程安全地监控您的宝宝、宠物、家庭、商业、交通和天气&#xf…...

Flask 验证码自动生成

Flask 验证码自动生成 想必验证码大家都有所了解&#xff0c;但是可以自己定义图片验证码&#xff0c;包含数字&#xff0c;英文以及数字计算&#xff0c;自动生成验证码。 生成图片以及结果 from captcha.image import ImageCaptchafrom PIL import Image from random impo…...

vmpwn小总结

前言&#xff1a; 好久没有更新博客了&#xff0c;关于vm的学习也是断断续续的&#xff0c;只见识了几道题目&#xff0c;但是还是想总结一下&#xff0c;所谓vmpwn就是把出栈&#xff0c;进栈&#xff0c;寄存器&#xff0c;bss段等单独申请一块空闲实现相关的功能&#xff0…...

开源密码管理器 Bitwarden 一站式管理所有密码以及 2FA

本文首发于只抄博客&#xff0c;欢迎点击原文链接了解更多内容。 前言 随着注册的平台越来越多&#xff0c;管理密码的难度也越来越高了。要是把密码都设置成一样的&#xff0c;担心哪天某个平台泄露被一锅端&#xff0c;而每个平台单独一个密码又不太好记&#xff0c;这时候就…...

标准体重计算API集成指南

标准体重计算API集成指南 引言 在当今数字化和健康意识日益增长的时代&#xff0c;开发人员和健康管理专业人士不断寻找创新的方法来促进用户的健康生活。标准体重计算是一个关键的健康指标&#xff0c;它可以帮助个人了解自己的身体状况&#xff0c;并为制定合适的饮食和运动…...

多个终端查看的history不一样,如何确保多个终端会话之间的 history 一致,减少历史记录差异

问题&#xff1a; 在使用 Linux 系统时&#xff0c;history 命令显示的历史记录通常是与当前终端会话相关的。这就意味着&#xff0c;如果你在多个终端中打开会话&#xff0c;它们显示的历史记录可能不完全相同。这个问题通常是由以下原因引起的&#xff1a; 原因&#xff1a…...

Spring Boot整合EasyExcel并行导出及Zip压缩下载

1. 项目依赖 首先&#xff0c;我们需要引入相关的依赖&#xff0c;包括 Spring Boot 和阿里巴巴的 EasyExcel 组件&#xff0c;此外还需要使用 Java 的 Zip 工具进行压缩操作。 <dependencies><!-- Spring Web --><dependency><groupId>org.springfr…...

Docker 对 iptables 规则的自动配置,这句话是什么意思

Docker 对 iptables 规则的自动配置指的是 Docker 守护进程 (daemon) 会自动管理 Linux 系统上的 iptables 规则&#xff0c;以便容器可以正确地进行网络通信。这对于大多数用户来说是一个方便的功能&#xff0c;因为它简化了容器网络配置。 具体来说&#xff0c;这意味着&…...

使用aarch64-unknown-linux-musl编译生成静态ARM64可执行文件

使用aarch64-unknown-linux-musl编译生成静态ARM64可执行文件 使用aarch64-unknown-linux-musl编译生成静态ARM64可执行文件1. 安装aarch64-unknown-linux-musl目标2. 安装交叉编译工具链安装musl-cross-make 3. 配置Rust编译器使用交叉编译工具链4. 编译你的Rust项目5. 运行或…...

【SpringBoot中出现循环依赖错误】

SpringBoot中出现循环依赖错误 在Spring Boot中&#xff0c;循环依赖&#xff08;circular dependency&#xff09;是指两个或多个bean相互依赖&#xff0c;形成一个闭合的依赖环。例如&#xff0c;Bean A依赖于Bean B&#xff0c;而Bean B又反过来依赖于Bean A。这种情况下&a…...

数据仓库-基于角色的权限管理(RBAC)

什么是基于角色的用户管理&#xff1f; 基于角色的用户管理(Role-Based Access Control&#xff0c;简称RBAC)是通过为角色赋予权限&#xff0c;用户通过成为适当的角色而得到这些角色的权限。 角色是一组权限的抽象。 使用RBAC可以极大简化对权限的管理。 什么是RBAC模型&…...

springboot3整合javafx解决bean注入问题

springboot整合javafx时候&#xff0c;很多问题就在于controller没有被spring容器管理&#xff0c;无法注入bean&#xff0c;在这里提供一套自己的解决思路 执行逻辑 这里仅仅提供一个演示&#xff0c;我点击按钮之后&#xff0c;从service层返回一个文本并显示 项目结构 创…...

.NET 8 Blazor Web项目中的 .razor 文件与 .cshtml 文件的本质区别

在.NET 8 Blazor Web项目中&#xff0c;.razor 和 .cshtml 文件是常用的视图文件格式。尽管它们看起来有相似之处&#xff0c;但在使用方式、功能和渲染机制上有着根本的不同。理解它们的本质区别&#xff0c;有助于开发者更好地选择合适的文件格式&#xff0c;并构建符合需求的…...

SpringBoot快速使用

一些名词的碎碎念: 1> 俩种网络应用设计模式 C/S 客户端/服务器 B/S 浏览器/服务器 俩者对比: 2> 集群和分布式的概念 集群: 分布式: 例子: 一个公司有一个人身兼多职 集群: 招聘N个和上面这个人一样身兼多职 分布式: 招聘N个人,分担上面这个人的工作,进行工作的拆分. 工…...

怎么建设商业网站/中国网站建设公司

/^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$/...

政府网站建设大事记/霸榜seo

2019独角兽企业重金招聘Python工程师标准>>> 虚拟机的网络连接里的“本地连接”就用“自动获取IP地址”就好&#xff0c;有固定IP的需要到“Internet协议”设置。&#xff08;右键“本地连接”&#xff0d;双击“Internet 协议”,看看是不是自动的吧&#xff01;固定…...

广州互联网大厂公司有哪些/怎么优化

程序运行的时候&#xff0c;需要内存空间存放数据。一般来说&#xff0c;系统会划分出两种不同的内存空间&#xff1a;一种叫做stack&#xff08;栈&#xff09;&#xff0c;另一种叫做heap&#xff08;堆&#xff09;。 区别&#xff1a;stack是有结构的&#xff0c;每个区块按…...

网站建设方面的/百度一下你就知道官网百度

oracle数据库有几十个后台进程&#xff0c;常常讨论哪些后台进程是致命的&#xff0c;有些进程kill会导致实例立即重启&#xff0c;常识中像smon, pmon,lgwr,ckpt.Unnn(container process for thread). , 但是有些进程kill并不会影响实例可用性&#xff0c; 甚至会立即进程级重…...

wordpress如何上传mp3/网站优化排名易下拉霸屏

JDBC简介 l数据库驱动 SUN公司为了简化、统一对数据库的操作&#xff0c;定义了一套Java操作数据库的规范&#xff0c;称之为JDBC lJDBC全称为&#xff1a;Java Data Base Connectivity&#xff08;java数据库连接&#xff09;&#xff0c;它主要由接口组成。 l组成JDBC的&…...

烟台建设/廊坊seo网络推广

androidAndroid活动生命周期&#xff0c;如果是Android Developer访谈中最常被问到的问题之一。 它也是一个容易搞砸的人。 您必须已经从developer.android.com和许多android开发书籍中看到了此活动生命周期图。 资料来源&#xff1a;developer.android.com但这还不够。 该图仅…...