📝 添加shared_memory文档

This commit is contained in:
snowy 2024-08-17 00:18:06 +08:00
parent 85a13251a5
commit b356524a9e
5 changed files with 70 additions and 25 deletions

View File

@ -5,13 +5,15 @@ order: 4
category: 开发 category: 开发
--- ---
## 简介 ## **通道通信**
### 简介
轻雪运行在主进程 MainProcess 里,其他插件框架进程是伴随的子进程,因此无法通过内存共享和直接对象传递的方式进行通信,轻雪提供了一个通道`Channel`用于跨进程通信,你可以通过`Channel`发送消息给其他进程,也可以监听其他进程的消息。 轻雪运行在主进程 MainProcess 里,其他插件框架进程是伴随的子进程,因此无法通过内存共享和直接对象传递的方式进行通信,轻雪提供了一个通道`Channel`用于跨进程通信,你可以通过`Channel`发送消息给其他进程,也可以监听其他进程的消息。
例如子进程接收到用户信息需要重启机器人,这时可以通过通道对主进程发送消息,主进程接收到消息后重启对应子进程。 例如子进程接收到用户信息需要重启机器人,这时可以通过通道对主进程发送消息,主进程接收到消息后重启对应子进程。
## 快速开始 ### 快速开始
通道是全双工的,有两种接收模式,但一个通道只能使用一种,即被动模式和主动模式,被动模式由`chan.on_receive()`装饰回调函数实现,主动模式需调用`chan.receive()`实现 通道是全双工的,有两种接收模式,但一个通道只能使用一种,即被动模式和主动模式,被动模式由`chan.on_receive()`装饰回调函数实现,主动模式需调用`chan.receive()`实现
@ -77,4 +79,24 @@ async def on_startup():
..-..-.. ..:..:.. [ℹ️信息] Passive receive: I am liteyuki main process passive ..-..-.. ..:..:.. [ℹ️信息] Passive receive: I am liteyuki main process passive
..-..-.. ..:..:.. [ℹ️信息] Active receive: I am liteyuki main process active ..-..-.. ..:..:.. [ℹ️信息] Active receive: I am liteyuki main process active
... ...
``` ```
## **共享内存通信**
### 简介
- 相比于普通进程通信,内存共享使得代码编写更加简洁,轻雪框架提供了一个内存共享通信的接口,你可以通过`storage`模块实现内存共享通信
- 内存共享是线程安全的,你可以在多个线程中读写共享内存,线程锁会自动保护共享内存的读写操作
### 快速开始
- 在任意进程中均可使用
```python
from liteyuki.comm.storage import shared_memory
shared_memory.set("key", "value") # 设置共享内存
value = shared_memory.get("key") # 获取共享内存
```
- 源代码:[liteyuki/comm/storage.py](https://github.com/LiteyukiStudio/LiteyukiBot/blob/main/liteyuki/comm/storage.py)

View File

@ -0,0 +1,24 @@
---
title: 内存共享通信
icon: exchange-alt
order: 5
category: 开发
---
# 简介
相比于普通进程通信,内存共享使得代码编写更加简洁,轻雪框架提供了一个内存共享通信的接口,你可以通过`shared_memory`模块实现内存共享通信
内存共享是线程安全的,你可以在多个线程中读写共享内存,线程锁会自动保护共享内存的读写操作
## 快速开始
- 在任意进程中均可使用
```python
from liteyuki.comm.storage import shared_memory
shared_memory.set("key", "value") # 设置共享内存
value = shared_memory.get("key") # 获取共享内存
```
- 源代码:[liteyuki/comm/storage.py](https://github.com/LiteyukiStudio/LiteyukiBot/blob/main/liteyuki/comm/storage.py)

View File

@ -1,13 +1,10 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
@Time : 2024/7/26 下午10:36
@Author : snowykami
@Email : snowykami@outlook.com
@File : __init__.py
@Software: PyCharm
该模块用于轻雪主进程和Nonebot子进程之间的通信 该模块用于轻雪主进程和Nonebot子进程之间的通信
依赖关系
event -> _
storage -> channel
rpc -> channel, storage
""" """
from liteyuki.comm.channel import ( from liteyuki.comm.channel import (
Channel, Channel,

View File

@ -136,8 +136,9 @@ class KeyValueStoreNoLock:
if IS_MAIN_PROCESS: if IS_MAIN_PROCESS:
return self._store.get(key, default) return self._store.get(key, default)
else: else:
self.passive_chan.send(("get", key, default)) temp_chan = Channel("temp_chan")
return self.active_chan.receive() self.passive_chan.send(("get", key, default, temp_chan))
return temp_chan.receive()
def delete(self, key: str, ignore_key_error: bool = True) -> None: def delete(self, key: str, ignore_key_error: bool = True) -> None:
""" """
@ -169,8 +170,9 @@ class KeyValueStoreNoLock:
if IS_MAIN_PROCESS: if IS_MAIN_PROCESS:
return self._store return self._store
else: else:
self.passive_chan.send(("get_all",)) temp_chan = Channel("temp_chan")
return self.active_chan.receive() self.passive_chan.send(("get_all", temp_chan))
return temp_chan.receive()
class GlobalKeyValueStore: class GlobalKeyValueStore:
@ -197,28 +199,29 @@ if IS_MAIN_PROCESS:
@shared_memory.passive_chan.on_receive(lambda d: d[0] == "get") @shared_memory.passive_chan.on_receive(lambda d: d[0] == "get")
def on_get(d): def on_get(data: tuple[str, str, any, Channel]):
shared_memory.active_chan.send(shared_memory.get(d[1], d[2])) data[3].send(shared_memory.get(data[1], data[2]))
@shared_memory.passive_chan.on_receive(lambda d: d[0] == "set") @shared_memory.passive_chan.on_receive(lambda d: d[0] == "set")
def on_set(d): def on_set(data: tuple[str, str, any]):
shared_memory.set(d[1], d[2]) shared_memory.set(data[1], data[2])
@shared_memory.passive_chan.on_receive(lambda d: d[0] == "delete") @shared_memory.passive_chan.on_receive(lambda d: d[0] == "delete")
def on_delete(d): def on_delete(data: tuple[str, str]):
shared_memory.delete(d[1]) shared_memory.delete(data[1])
@shared_memory.passive_chan.on_receive(lambda d: d[0] == "get_all") @shared_memory.passive_chan.on_receive(lambda d: d[0] == "get_all")
def on_get_all(d): def on_get_all(data: tuple[str, Channel]):
if d[0] == "get_all": if data[0] == "get_all":
shared_memory.active_chan.send(shared_memory.get_all()) data[1].send(shared_memory.get_all())
else: else:
# 子进程在入口函数中对shared_memory进行初始化
shared_memory = None shared_memory = None
_ref_count = 0 # 引用计数 _ref_count = 0 # import 引用计数, 防止获取空指针
if not IS_MAIN_PROCESS: if not IS_MAIN_PROCESS:
if (shared_memory is None) and _ref_count > 1: if (shared_memory is None) and _ref_count > 1:
raise RuntimeError("Shared memory not initialized.") raise RuntimeError("Shared memory not initialized.")

View File

@ -1,6 +1,5 @@
import threading import threading
from nonebot import logger
from liteyuki.comm.channel import active_channel from liteyuki.comm.channel import active_channel