un

guest
1 / ?
back to lessons

Como um Intertangle Forma

Dois subsistemas começam a vida como módulos independentes. Com o tempo, cada um acumula um campo em um objeto-deus compartilhado: uma estrutura de configuração global, um gerenciador singleton, uma classe estática. Cada adição: correta em isolamento. O acoplamento: invisível em testes de pequena escala.

Padrão Intertangido: Sistema A e B compartilhando estado global sem snapshot ou interface

Três substratos onde isso calcificou:

VLC player de mídia. Áudio, vídeo e playlist compartilham um único lock guardando um estado de player global. Uma solicitação de pulo para um ponto de tempo adquire o lock, modifica a posição de reprodução e esvazia o buffer de áudio. O subsistema de vídeo, esperando pelo mesmo lock, fica parado. O subsistema de playlist, também esperando, não pode fazer prefetch. Resultado: três subsistemas independentes serializados através de um único objeto de estado. Custo de desempenho: O(N) contentão de lock onde N é o número de subsistemas, todos proporcional à latência da operação.

Loop de eventos Redis. AOF fsync (gravação no disco), replicação (gravação na rede) e execução de comando (CPU) compartilham o único loop de eventos. Cada um: correto em isolamento. Um fsync lento faz parar a execução de comando. Atraso na replicação agrava sob carga de escrita. O ponto de acoplamento: um único contexto de execução compartilhado por operações com perfis de latência diferentes.

LevelDB VersionSet. Caminho de escrita (flush de memtable) e compactação de fundo compartilham o lock de VersionSet. Um trabalho de compactação mantém o lock por dezenas de milissegundos. Caminho de escrita para para. Ambas as operações: necessárias. O acoplamento: estrutural, não de tempo.

A Distinção Crítica

Um Intertangle tem um acoplamento estrutural, não um problema de tempo. Uma condição de corrida: dois threads acessam estado compartilhado sem sincronização. Correção: adicione um mutex.

Um Intertangle: dois subsistemas compartilham estado por design. Adicionar um mutex não corrige o acoplamento; ele serializa o acesso. Os subsistemas ainda compartilham estado. A garganta se aperta.

Adicionar um mutex a um Intertangle de VLC torna isso pior: agora áudio, vídeo e playlist esperam por um único lock. A correção estrutural: dê a cada subsistema seu próprio estado. Captura de fase: congela um snapshot do estado compartilhado na fronteira de fase, permitindo que cada subsistema leia o snapshot independentemente, mesclando as escritas de volta no final.

Estrutural vs Tempo

A questão diagnóstica chave para um Intertangle: um mutex resolveria o problema ou apenas tornaria tudo pior?

Uma condição de corrida: um mutex resolve o problema. O acesso correto elimina a corrupção.

Um Intertangle: um mutex serializa o acesso, mas preserva o acoplamento estrutural. Os sub-sistemas ainda compartilham estado. Sob carga, eles ainda se bloqueiam. A garganta se estreita.

Descreva como dois subsistemas poderiam se entrelaçar. O que torna isso estrutural em vez de apenas uma condição de corrida?

Como encontrar um Intertangle

Três sinais de detecção:

1. Campos mutáveis compartilhados entre sub-sistemas. Um objeto divino com campos lidos e escritos por mais de um sub-sistema. Se remover o acesso aos campos de um sub-sistema quebrar outro sub-sistema, eles compartilham estado.

2. Mutex único protegendo operações não relacionadas. Um lock protegendo a flush de áudio E a decodificação de vídeo E a recuperação da playlist: três sub-sistemas com diferentes perfis de latência, todos esperando um pelo outro. O cheiro: operações não relacionadas com o mesmo nome de lock.

3. Regressão de desempenho quando a carga aumenta. Latência para a operação A aumenta quando a operação B corre em concorrência, mesmo que A e B pareçam independentes. Eles não são independentes: eles compartilham estado.

A solução de captura de fase

Padrão de captura de fase:

# ANTES: sub-sistemas leem e escrevem diretamente no estado compartilhado
class GameWorld:
    position = {}  # mutable compartilhado
    velocity = {}  # mutable compartilhado

def physics_tick(world):
    for entity in world.entities:
        world.position[entity] += world.velocity[entity]  # escreve estado compartilhado no meio do loop
# DEPOIS: snapshot congelado antes da fase; as escritas vão para o buffer next_state
def physics_tick(world):
    snapshot = world.freeze()  # visualização imutável
    next_state = {}
    for entity in snapshot.entities:
        next_state[entity] = snapshot.position[entity] + snapshot.velocity[entity]
    world.merge(next_state)  # fusão atômica na fronteira da fase

Cada sub-sistema lê o snapshot. Nenhum sub-sistema escreve nele. As escritas acumulam-se em um buffer e se fundem atomicamente na fronteira da fase. Os sub-sistemas agora executam independentemente: não há contenção de trancas, nenhuma dependência de ordem, nenhuma conexão oculta.

Aplicar a correção

Um time relata um defeito: o motor de jogo de animação e o sistema de colisão ambos escrevem em um objeto transform de entidade compartilhada. Quando ambos correm no mesmo tick, os resultados de colisão dependem de se a animação correu primeiro. Adicionar um mutex corrigiu a ordem, mas agora a animação fica travada sempre que a colisão executa uma varredura de larga fase.

Nomeie a classe de defeito. Explique por que adicionar o mutex não foi a solução. Descreva a correção estrutural.