FC成环器内部真的是个环么

FC成环器并非简单地维持一个物理环形结构。为解决FC-AL仲裁环效率低下的问题,通过采用Crossbar交换电路实现数据直接交换,既保留了FCAL协议又提升了性能。

FC成环器内部真的是个环么

       我们知道在FC流行的时代,控制器与硬盘之间的连接方式是FC-AL仲裁环。环上的所有节点手拉手连接起来,将数据在这个大环上传递,每个节点根据数据包的FCAL地址来判断是不是给自己,的是就收下,不是就继续往外扔,直到某个节点认领。

         然而,如果盘数一增多,那么手拉手接力传数据的方式显然效率是很低的。而且FCAL环有个毛病就是必须按照一个方向传递,同时它还是个同步环,也就是环上同一时刻只有两个节点之间在互传数据,其他节点只起到接力的作用。这显然效率也很低,理论上完全可以做到环内任意两个点之间可以同时并行传输数据。但是FC协议刚出现的时候,那时候瓶颈其实还不在于FC传递上,而在于FC网络节点的性能自身。比如机械硬盘平均处理每个IO耗费10ms,而FCAL环路就算绕一大圈也不过几百微秒的时延,相比机械硬盘的慢速响应而言微不足道。但是随着FCAL环接入硬盘数量的不断增加,系统需要同时将指令发送给多个硬盘并行处理,并发请求数量上来之后,FCAL的同步特性就严重制约了并发度。

         于是人们就在想能否让数据一条直达。当FC协议在传统存储系统中得到大量普及之后,业界做FC成环器的厂商比如当时的PMC-Sierra公司,就发明了一种直接交换而不用大家手拉手接力传递的成环芯片,其内部其实是个Crossbar交换电路了,只不过依然需要遵循FCAL的协议,也就是先仲裁,后传数据。


         其内部的固件负责接收仲裁广播,并直接独立裁决,也就是不将这笔广播发送到FC环路上真的让大家参与仲裁,因为这样会非常慢。裁决模块会均衡的让所有人都有机会获得仲裁胜利。仲裁模块会直接返回仲裁成功结果给发起端,降低了时延,于是发起端直接开始传送数据,发起端节点并不知道该数据是怎么传递到目的的,它认为底层还是大家帮忙接力传过去的。而实际上,是由成环器芯片通过Crossbar电路直接交换到对端的。利用这种方式,既能保持对上层协议的不修改、对节点固件的不修改,还能够提升性能。


这是目前的代码from rdkit import Chem from rdkit.Chem import AllChem import torch from torch_geometric.data import Data from rdkit.Chem import Descriptors from rdkit.Chem.rdmolfiles import MolToXYZFile def calc_descriptors(mol): return { "MW": Descriptors.MolWt(mol), # 分子量 "LogP": Descriptors.MolLogP(mol), # 脂水分配系数 "HBD": Descriptors.NumHDonors(mol), # 氢键供体 "HBA": Descriptors.NumHAcceptors(mol), # 氢键受体 "TPSA": Descriptors.TPSA(mol), # 极性表面积 "RotBonds": Descriptors.NumRotatableBonds(mol) # 可旋转键 } def smi_to_graph(smi_file): """将.smi文件转换为分子图数据集""" data_list = [] with open(smi_file) as f: for line in f: smi, name = line.strip().split('\t') # 假设格式: SMILES\tName # 转换为分子对象 mol = Chem.MolFromSmiles(smi) if mol is None: continue # 添加氢原子并生3D构象 mol = Chem.AddHs(mol) AllChem.EmbedMolecule(mol, randomSeed=42) # 原子特征矩阵 atom_features = [] for atom in mol.GetAtoms(): features = [ atom.GetAtomicNum(), # 原子序数 atom.GetDegree(), # 连接度 atom.GetHybridization().real, # 杂化类型 atom.GetFormalCharge(), # 形式电荷 atom.GetIsAromatic() # 芳香性 ] atom_features.append(features) x = torch.tensor(atom_features, dtype=torch.float) # 边索引和边特征 edge_index = [] edge_attr = [] for bond in mol.GetBonds(): i = bond.GetBeginAtomIdx() j = bond.GetEndAtomIdx() edge_index.append([i, j]) edge_index.append([j, i]) # 无向图需双向添加 bond_features = [ bond.GetBondTypeAsDouble(), # 键类型 bond.IsInRing(), # 是否 bond.GetIsConjugated() # 共轭性 ] edge_attr.append(bond_features) edge_attr.append(bond_features) # 对应双向边 edge_index = torch.tensor(edge_index, dtype=torch.long).t().contiguous() edge_attr = torch.tensor(edge_attr, dtype=torch.float) data_list.append(Data( x=x, edge_index=edge_index, edge_attr=edge_attr, name=name, smiles=smi )) return data_list # 转换.smi文件 dataset = smi_to_graph(r"D:\PyCharm 2025.2.0.1\project\分子数据.smi") import torch.nn.functional as F from torch_geometric.nn import GCNConv, global_mean_pool class GNNPredictor(torch.nn.Module): def __init__(self, node_dim, hidden_dim=128, out_dim=1): super().__init__() self.conv1 = GCNConv(node_dim, hidden_dim) self.conv2 = GCNConv(hidden_dim, hidden_dim) self.fc = torch.nn.Sequential( torch.nn.Linear(hidden_dim, 64), torch.nn.ReLU(), torch.nn.Linear(64, out_dim) ) def forward(self, data): x, edge_index, batch = data.x, data.edge_index, data.batch # 图卷积层 x = F.relu(self.conv1(x, edge_index)) x = F.dropout(x, p=0.3, training=self.training) x = F.relu(self.conv2(x, edge_index)) # 全局池化 x = global_mean_pool(x, batch) # 全连接层 return self.fc(x) from torch_geometric.loader import DataLoader from sklearn.model_selection import train_test_split # 添加标签(示例:载药量) #for data in dataset: # data.y = torch.tensor([get_loading(data.smiles)], dtype=torch.float) # 数据集划分 train_data, test_data = train_test_split(dataset, test_size=0.2, random_state=42) train_loader = DataLoader(train_data, batch_size=32, shuffle=True) test_loader = DataLoader(test_data, batch_size=32, shuffle=False) device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') model = GNNPredictor(node_dim=5).to(device) optimizer = torch.optim.Adam(model.parameters(), lr=0.001) criterion = torch.nn.MSELoss() for epoch in range(100): model.train() total_loss = 0 for batch in train_loader: batch = batch.to(device) optimizer.zero_grad() pred = model(batch).view(-1) loss = criterion(pred, batch.y) loss.backward() optimizer.step() total_loss += loss.item() print(f"Epoch {epoch}, Loss: {total_loss / len(train_loader):.4f}")请帮我改正
08-27
<think>嗯,用户想了解链表的概念以及检测和处理方法。首先,我需要回忆链表的基本定义。链表指的是链表的某个节点的next指针指向了链表中之前的一个节点,导致链表形一个闭,无法正常到达末尾的null节点。这点我记得没错,但需要确认是否有更准确的说法。 接下来是检测方法。常见的检测方法有哈希表法和快慢指针法。哈希表法的思路是遍历链表,记录每个访问过的节点,如果遇到重复的节点就说明存在。这种方法的时间复杂度是O(n),但空间复杂度也是O(n),因为需要存储所有节点。而快慢指针法则用两个指针,一个每次走两步,一个每次走一步,如果存在,它们最终会相遇。这种方法的空间复杂度是O(1),更高效。需要详细解释这两种方法的步骤,并指出它们的优缺点。 用户可能还关心如何处理,比如如何找到的入口节点。根据快慢指针相遇后,将其中一个指针移回链表头,然后两个指针以相同速度前进,再次相遇的节点就是的入口。这部分需要结合数学证明,可能用户需要了解推导过程,但可能不需要太深入,所以简要说明即可。 另外,用户提供的引用中有形链表II的问题,说明可能涉及到LeetCode题目,需要结合实际问题举例。例如,引用[2]提到的形链表II需要找到的入口,这可能要详细说明算法步骤。 还要考虑代码实现的问题。用户提供的引用[3]和[5]中有链表节点的定义和交换节点的例子,可能需要给出检测的代码示例,比如快慢指针的实现,以及找到入口的代码。 需要检查是否覆盖了所有用户的问题:定义、检测方法、处理步骤。是否有遗漏?比如,如何处理存在的链表,是否需要断开?或者应用场景是什么?但用户的问题主要集中在检测,可能不需要深入处理后的操作,但简要提及可能有帮助。 另外,引用[1]提到链表用于集合表示,这可能与问题无关,但引用[5]中的节点交换步骤可能相关,但不确定。可能需要忽略无关引用,专注于与相关的引用。 最后,生相关问题时要围绕链表,例如检测方法的时间复杂度、如何找到的长度、实际应用中的处理等。确保问题有逻辑关联,帮助用户进一步学习。</think>### 链表的定义及检测方法 #### 1. 链表的定义 链表是指链表中某个节点的`next`指针指向链表中**其之前的某个节点**,导致链表遍历时无法到达末尾的`null`,形一个闭合循。例如: $$A \rightarrow B \rightarrow C \rightarrow D \rightarrow B$$ 此时节点`D`的`next`指针指向`B`,形`B→C→D→B`[^2]。 --- #### 2. 检测链表的方法 ##### (1) 哈希表法 - **步骤**:遍历链表,将访问过的节点存入哈希表。若遇到节点已存在于表中,则存在。 - **时间复杂度**:$O(n)$ - **空间复杂度**:$O(n)$(需存储所有节点) - **代码示例**(Python): ```python def hasCycle(head): visited = set() while head: if head in visited: return True visited.add(head) head = head.next return False ``` ##### (2) 快慢指针法(Floyd判圈算法) - **步骤**: 1. 快指针每次移动两步,慢指针每次移动一步。 2. 若两指针相遇,则存在;若快指针遇到`null`,则无。 - **数学原理**:假设外有$a$个节点,内有$b$个节点。相遇时,慢指针走了$s$步,快指针走了$2s$步。此时$2s - s = nb$($n$为整数),即$s = nb$。进一步可推导出入口的位置[^2]。 - **时间复杂度**:$O(n)$ - **空间复杂度**:$O(1)$ - **代码示例**(Python): ```python def hasCycle(head): slow = fast = head while fast and fast.next: slow = slow.next fast = fast.next.next if slow == fast: return True return False ``` --- #### 3. 处理链表中的 若需要**找到的入口节点**(如LeetCode 142题): 1. 使用快慢指针确认存在。 2. 将其中一个指针重置到链表头,两指针以相同速度移动。 3. 再次相遇的节点即为入口。 ```python def detectCycle(head): slow = fast = head while fast and fast.next: slow = slow.next fast = fast.next.next if slow == fast: slow = head # 重置慢指针 while slow != fast: slow = slow.next fast = fast.next return slow return None ``` --- #### 4. 应用场景 - **内存管理**:检测循引用。 - **图算法**:判断图中是否存在路(如DFS遍历时标记访问状态)。 - **数学问题**:如判断伪随机数序列的周期性[^1]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值