Às vezes, você apenas possui algoritmos que não podem ser melhores que o tempo linear, para os quais ainda há uma forte demanda de desempenho.
Um exemplo é o processamento de vídeo em que você não pode tornar uma imagem / quadro mais brilhante como um exemplo básico sem percorrer todos os pixels (bem, suponho que você possa com algum tipo de estrutura hierárquica indicando propriedades herdadas por crianças que acabam descendo para blocos de imagem para nós de folha, mas você adiaria um custo mais alto de loop através de cada pixel para o renderizador e o código provavelmente seria mais difícil de manter do que o filtro de imagem mais otimizado para micro).
Existem muitos casos assim no meu campo. Costumo fazer loops de complexidade linear mais que precisam tocar em tudo ou ler tudo do que aqueles que se beneficiam de qualquer tipo de estrutura ou algoritmo sofisticado de dados. Não há trabalho que possa ser pulado quando tudo tiver que ser tocado. Portanto, nesse ponto, se você inevitavelmente estiver lidando com complexidade linear, precisará tornar o trabalho realizado por iteração cada vez mais barato.
Portanto, no meu caso, as otimizações mais importantes e comuns são frequentemente representações de dados e layouts de memória, multithreading e SIMD (normalmente nessa ordem, com a representação de dados sendo a mais importante, pois afeta a capacidade de executar as duas últimas). Não estou enfrentando tantos problemas que são resolvidos por árvores, tabelas de hash, algoritmos de classificação e coisas desse tipo. Meu código diário está mais na linha de "para cada coisa, faça alguma coisa".
É claro que é outro caso para discutir quando as otimizações são necessárias (e mais importante, quando não são), micro ou algorítmicas. Mas no meu caso particular, se um caminho de execução crítico precisar de otimização, os ganhos de velocidade 10x + são frequentemente alcançados por otimizações de nível micro, como multithreading, SIMD e reorganizando layouts de memória e padrões de acesso para melhorar a localidade de referência. Não é tão frequente que, digamos, substitua um tipo de bolha por um tipo introsort ou tipo radix ou detecção de colisão de complexidade quadrática por um BVH tanto quanto encontro pontos de acesso que, por exemplo, se beneficiam da divisão de campo quente / frio.
Agora, no meu caso, meu campo é tão crítico para o desempenho (rastreamento de raios, mecanismos físicos, etc.) que um rastreador de raios lento, mas perfeitamente correto, que leva 10 horas para renderizar uma imagem, é frequentemente considerado inútil ou mais do que rápido, completamente interativo, mas produz as imagens mais feias, com raios vazando em todos os lugares devido à falta de interseção estanque de raios / tri. A velocidade é sem dúvida a principal métrica de qualidade desse software, sem dúvida até mais do que correção até certo ponto (uma vez que "correção" é uma ideia difusa do raytracing, pois tudo está se aproximando, desde que não esteja travando ou algo assim). E quando for esse o caso, se eu não pensar em eficiência antecipadamente, acho que preciso alterar o código no nível de design mais caro para lidar com designs mais eficientes. Então, se eu não
O jogo é outro campo semelhante ao meu. Não importa o quão correta é a lógica do jogo ou a manutenção e a engenharia da sua base de código, se o jogo for executado a 1 quadro por segundo, como uma apresentação de slides. Em certos campos, a falta de velocidade pode realmente tornar o aplicativo inútil para seus usuários. Ao contrário dos jogos, não existe uma métrica "boa o suficiente" em áreas como raytracing. Os usuários sempre querem mais velocidade, e a concorrência industrial é predominantemente na busca de soluções mais rápidas. Nunca será bom o suficiente até que seja em tempo real, quando os jogos estarão usando rastreadores de caminho. E então provavelmente ainda não será bom o suficiente para o VFX, pois os artistas podem querer carregar bilhões de polígonos e ter simulações de partículas com auto-colisão entre bilhões de partículas a mais de 30 FPS.
Agora, se for de algum conforto, apesar disso ainda escrevo cerca de 90% do código em uma linguagem de script (Lua) sem preocupações com o desempenho. Mas eu tenho uma quantidade invulgarmente grande de código que realmente precisa percorrer milhões a bilhões de coisas e, quando você percorre milhões a bilhões de coisas, começa a notar uma diferença épica entre o código ingênuo de thread único que invoca uma falta de cache a cada iteração versus, digamos, código vetorizado executando em paralelo acessando blocos contíguos onde nenhum dado irrelevante é carregado em uma linha de cache.