Como ter sucesso na programação do sistema, o que você precisa saber e entender, especialmente se você trabalha na terceira década? C # e desempenho - vale a pena reescrever tudo o que você vê em C #? Qual é o futuro das tecnologias de compilador de baixo nível que nos aguardam?
Hoje em nosso estúdio virtual,
Alexandre Mutel responde a perguntas.

Alexandre Mutel é arquiteto líder de software da Unity Technologies. Além disso, ele é um conhecido desenvolvedor de código aberto, contribuindo para SharpDX, Markdig, Zio e outros projetos, e desde 2014 - MVP na categoria Visual Studio and Development Technologies.
Alexandre trabalha em uma variedade de questões de baixo e alto nível nas áreas de renderização gráfica em tempo real, GPGPU, síntese de som, uso e arquitetura eficientes de linguagens gerenciadas, geração de código e documentação.
Como sempre, as entrevistas são conduzidas por Evgeny Trifonov (
phillennium ) e Oleg Chirukhin (
olegchir ) do Grupo JUG.ru.

No final do post, há uma surpresa de Dylan Beatty (outro doador famoso) - nós mesmos não esperávamos.
E.: Você tem uma longa carreira, três décadas - para começar, você pode falar brevemente sobre isso?Tudo começou na infância - eu tenho o Amstrad PC 464. Quando comecei a programar neste computador, eu tinha 11 ou 12 anos, não me lembro exatamente. Eu rapidamente dominei a programação BASIC e comprei livros sobre desenvolvimento de jogos: então parecia muito interessante. Joguei muito poucos jogos, onde era mais interessante desenvolver e escrever código. Então eu continuei escrevendo código assembler para a Amstrad.
Aos 16 anos, comprei um Amiga 500. Conheci caras que estavam escrevendo demos - não era mais o que é agora. Agora, este é o WebGL, e este é um demosceno completamente diferente. Comecei a escrever muitas demos, que nem sempre mostrava, mas eu gostava de escrever em assembler. E era assim tão simples.
Então ele foi para uma faculdade tecnológica, onde estudou engenharia da computação. Isso já era algo completamente diferente em comparação com jogos e montador. Adorei aprender coisas que nem sabia que existiam antes: sistemas operacionais, UNIX, trabalhando com a linguagem C (antes eu usava o BASIC ou o assembler apenas porque não tinha dinheiro para comprar um compilador C / C ++).
Quando se formou na faculdade, começou a trabalhar no mercado de câmbio. Este era um trabalho para uma empresa francesa em Nova York. Dois anos depois, voltei e fui ao banco. Na verdade, eu não queria trabalhar em um banco, queria trabalhar no desenvolvimento de jogos. Mas, como resultado, preso em uma nova área, muitas coisas podem ser aprendidas. Então passei 8-9 anos lá, lidando principalmente com Java e um pouco com C ++. Muitos servidores distribuídos e bancos de dados SQL, copiando bancos de dados ... Não é o que estou fazendo agora.
Então tirei umas férias criativas e fiz uma viagem turística ao redor do mundo: eu estava na África, na América do Sul, um ano inteiro na Ásia. A jornada me mudou e me sacudiu. Quando voltei, não podia mais trabalhar com computadores, na área de TI, não podia trabalhar para o banco. Larguei o emprego e passei 4 anos em cursos de assistente social para trabalhar com crianças, sem-teto, deficientes e idosos. Estudei isso por três anos, e foi muito interessante, porque a maior parte da minha vida trabalhei no campo das ciências exatas: matemática, projetos, abstrações. E então ele de repente pegou e se mudou para uma área muito humanitária. Eu até tentei trabalhar nessa área após o treinamento, mas apenas durante esse período, um amigo com quem eu demos quando criança sugeriu que podemos fazer isso novamente.
Comecei a praticar demos todo o meu tempo livre, e muito rapidamente começou a levar mais do que trabalhar com crianças na rua. Isso foi ruim. As pessoas disseram: “Precisamos tentar encontrar trabalho no desenvolvimento de jogos, por que não? Você pode fazer isso. Mas achei que isso era impossível, porque não trabalhava com computadores há muito tempo e era difícil encontrar trabalho em TI com meu currículo.
Comecei a trabalhar em aplicativos de código aberto e lancei alguns projetos que as empresas começaram a usar. Uma vez que uma dessas empresas entrou em contato comigo, elas usaram um dos mais recentes projetos, chamado SharpDX. Fui ao Japão com minha família - porque já tinha dois filhos. Moramos 5 anos no Japão. No momento, eu estava trabalhando na criação de um mecanismo de jogo do zero em C #.
Cerca de dois anos atrás, voltei para a França e comecei a trabalhar na Unity. Isso interferiu no que eu fiz antes, mas eles se ofereceram para trabalhar em uma tarefa muito complexa e interessante, um teste real: criar um compilador nativo que gere código nativo a partir do código IL .NET. Era exatamente o que eu sempre quis fazer, mas não consegui, porque não teria sido pago por isso. E então houve uma chance, uma grande oportunidade. Eu trabalhei neste projeto por 2 anos.
Sim, parece que a história não é muito curta.
E.: Nada, essa carreira vale uma longa história. Por causa da sua experiência, eu gostaria de lhe perguntar isso. Agora, algumas pessoas dizem: "A Lei de Moore não funciona mais, os computadores não ficam mais rápidos, estamos todos condenados". Outros respondem: "Vamos lá, apesar de não estarem acelerando no mesmo ritmo, ainda há crescimento, portanto não há motivo para entrar em pânico". Como o tópico da produtividade está próximo de você e, ao mesmo tempo, acompanha o setor há muito tempo, qual é a sua posição?Eu aderir a este meio de ouro.
(risos) Acredito que muitas, se não a maioria das aplicações que desenvolvemos, se adaptam aos requisitos de desempenho desde o início, resultando na melhor qualidade possível.
Veja o que aconteceu na indústria de TI diante de nossos olhos. Por exemplo, quando o Windows se tornou um pouco mais lento ao longo dos anos - Windows Vista, etc. De fato, foi feito um trabalho natural para melhorar o desempenho, porque durante anos não estava particularmente preocupado. Quando o Windows 8 saiu, já estava um pouco melhor. Em seguida, o Windows 10 saiu e ficou um pouco melhor. Como resultado, temos um sistema que funciona muito bem comparado ao que era antes. Foi realmente importante para eles fazer essas otimizações, porque uma vez que as pessoas necessariamente “viviam além de seus meios” e começavam a dizer: “Oh! Este software não funciona mais, estamos mudando para o Linux, porque é mais rápido e menos estúpido. "
O mesmo pode ser dito sobre todo o software que desenvolvemos. E o que é surpreendente: sempre houve uma tendência a trabalhar com código nativo; em algum momento, mesmo no Windows, eles decidiram retornar ao C ++, disseram: "O C ++ é uma solução, o .NET é muito lento, depois o Garbage Collector e o blá blá blá ... " E, novamente, os idiomas nativos se tornaram relevantes.
Ao mesmo tempo, o V8 no Chrome trouxe o JavaScript de volta ao uso graças ao JIT. JS é uma linguagem de script, não super rápida, mas às vezes funciona duas vezes mais rápido que C ++. Isso foi o suficiente para ele sobreviver e para usá-lo agora em coisas como escrever código no Visual Studio Code. Mas se você olhar de perto, é tudo porque os requisitos de desempenho foram estabelecidos lá desde o início. Mesmo no VSCode, embora exista muito código JavaScript e script em geral, tudo o resto - V8, pilha de renderização, JIT - tudo isso é escrito em uma linguagem projetada para obter o máximo desempenho, ou seja, em C ++. Tudo poderia ser escrito em outra linguagem, não necessariamente em C ++, mas o fato é que todo esse software foi desenvolvido levando em consideração o desempenho desde o início.
Portanto, sim, podemos usar linguagens menos eficientes e produtivas, mas apenas porque todas as tecnologias subjacentes são desenvolvidas com o objetivo de obter uma
experiência do usuário fantástica. Por exemplo, o Visual Studio Code é um software incrível que funciona muito bem para desenvolvedores e resolve seus problemas. Muitas pessoas dizem: “Embora gostemos de usar mais editores de código nativos, agora estamos migrando para o Código do Visual Studio” - porque eles consideram bastante eficaz. O desempenho está em toda parte, mas às vezes não o vemos porque já está incorporado em tudo o que usamos.
Pensamos: está escrito em JavaScript, porque é rápido o suficiente. Mas o JavaScript é tão rápido apenas porque centenas de centenas de engenheiros de desenvolvimento trabalham há anos para otimizar o JIT. Agora podemos usar linguagens de script mesmo para escrever aplicativos muito complexos. Linguagens de script que, sem todo esse trabalho preparatório, teriam sido muito mais lentas. Vivemos em tempos estranhos. Temos uma escolha, mas ainda há essa história de desempenho que se repete repetidamente para todos os idiomas.
Portanto, o .NET é um exemplo típico. Um grande trabalho foi feito nos últimos três a quatro anos. Se você observar o ASP.NET Core em algum momento, se observar todo o trabalho realizado com o CoreCLR ... O desempenho é uma coisa bem vendida, custa dinheiro e permite que você consiga mais. Tentando atender a requisitos rígidos, você pode tentar se tornar mais produtivo, economizar energia, economizar dinheiro no final do mês - o desempenho afeta tudo. Quando ouço as pessoas dizerem: “Tudo está em ordem, estou desenvolvendo meu aplicativo, ele tem desempenho médio, vai dar ...”, o que eles estão pensando? Você precisa de um tempo para verificar se você pode tornar seu aplicativo um pouco mais produtivo. Se você pode economizar recursos ou tempo de aplicação em pelo menos um décimo, isso é bom.
E.: Há parcialmente uma questão filosófica. Você acha que o Slack não é o melhor lugar para soluções técnicas, mas em seu site você se oferece para assinar o RSS da velha escola. Você acha que a nova era das mensagens instantâneas está tornando os desenvolvedores menos produtivos?Não, acho que não. Agora eu trabalho remotamente. No trabalho, na Unity, podemos trabalhar remotamente, então eu constantemente uso o Slack para me comunicar com os colegas. Essa é a melhor maneira de manter contato e permanecer produtivo. Isso leva muito tempo do trabalho, porque você precisa verificar os canais e assim por diante, mas posso desativar temporariamente o Slack e me concentrar no trabalho. Enquanto eu trabalhava na empresa em espaço aberto, não tive escolha: se alguém quiser fazer uma pergunta, você deve responder imediatamente, é muito mais complicado.
Quanto ao Twitter e e-mail, eu não os vero com tanta frequência. Uma ou duas vezes por dia que leio o Twitter, depende de vários fatores: se eu participo de alguma discussão e o que discuto. Se você usa algo como o Slack, pode ingressar em diferentes canais da empresa, pode seguir muitos tópicos que você não seria capaz de seguir se trabalhasse sozinho. Precisamos encontrar um meio termo: todos nos preocupamos com muitas coisas que acontecem na empresa, mas precisamos ser seletivos, porque você não pode participar de todas as discussões ao mesmo tempo. Algumas pessoas podem ler tantos canais que simplesmente fico impressionado com suas habilidades, eu mesmo não sou assim. Hoje eu li cerca de 30 canais, isso não é tanto.
E.: Obrigado, tempo para as perguntas de Oleg!R.: Minha carreira é um pouco semelhante à sua: trabalhei em um banco, agora em um campo completamente diferente - na organização de conferências e, ao mesmo tempo, estou tentando descobrir como construir compiladores. O que você pode aconselhar para aqueles que estão tentando mudar para a programação do sistema a partir de simples desenvolvedores corporativos da Web, existem dicas para essa transição? Estou certo de que não há o suficiente de nós aqui, o suficiente.Não tenho certeza se existe um caminho preparado para essa transição. Se você estiver interessado em tais tecnologias, faça um dever de casa comum. Em casa, você escreve analisadores e itens relacionados aos compiladores. Não é necessário escrever o compilador inteiro do começo ao fim, até a própria geração do código da máquina. Você se interessa em escrever a infraestrutura do compilador. É isso que venho fazendo nos últimos anos trabalhando na Unity. Se você é apaixonado por coisas de baixo nível, esse é um daqueles lugares onde você pode entender como tudo funciona na realidade. Como melhorar o trabalho, onde vale a pena melhorar o desempenho e onde isso ainda não foi feito. Se você está preocupado com o desempenho, é muito importante estar ciente do que o aplicativo será executado no final.
Desempenho é o meu tema, e tudo isso se tornou uma grande oportunidade para mim. Gostaria de abordar a solução do problema em sua essência, ou seja, no nível do compilador. É aqui que podemos aumentar a produtividade dezenas de vezes nos locais onde é necessário para nossos usuários. Se rodarmos jogos, aplicativos, filmes ou algo assim, às vezes pode ser relativamente fácil alcançar esses resultados.
Minha paixão por coisas de baixo nível e componentes do compilador me levou ao meu trabalho atual. Mas isso não era algo que eu especificamente queria fazer. Às vezes, quando você obtém muita experiência com idiomas diferentes, cria aplicativos - você até deseja criar seu próprio idioma. Comecei a fazer isso, mas parei porque é muito trabalho e tenho muito pouco tempo livre. Mas você tem um desejo subconsciente de voltar "às raízes", tentar fazer algo sozinho para entender tudo. Obviamente, eu entendi como os compiladores funcionam e tudo mais, mas não entendi a complexidade dos requisitos. Compensações complexas para lidar, por exemplo, no campo do gerenciamento de memória. É muito difícil escolher o que ao mesmo tempo proporcionará maior produtividade ao desenvolvedor de aplicativos e será eficaz. Esse problema ainda não foi resolvido até o fim. Rust ou .NET nunca resolverá isso. A ferrugem é linda, incrível, mas é difícil trabalhar com isso, especialmente se você estiver mudando para algo como JavaScript. No entanto, existem exemplos de desenvolvedores de Python ou JavaScript que estão migrando para o Rust, embora isso seja algo surpreendente.
A.: Você mencionou que programou em C # nos últimos 10 anos.Então, o que é bom em C #? Por que não C ++, por exemplo? C ++ parece ser uma linguagem mais sistêmica.Para ser sincero, odeio C ++, odeio C, mas trabalho com eles. Eu sinceramente acredito que eles levam a um monte de bugs, a uma enorme ineficiência no desenvolvimento. Muitas pessoas pensam que, como você está programando em C, você já está de fato escrevendo código rápido que seu programa será orientado para o desempenho. Isto não é verdade. Se você esculpir montes de malloc e tudo isso, será lento, mesmo em comparação com o que está escrito no .NET. Bons desenvolvedores de C / C ++ são forçados a usar truques como o
alocador de memória da
região . Você precisa se enterrar em um monte de coisas estranhas das quais ninguém ouviu falar. Embora aqui os desenvolvedores de jogos geralmente saibam sobre essas coisas. No mínimo, desenvolvedores AAA ou pessoas que fazem jogos em estruturas C / C ++. Alguns dos problemas decorrem da complexidade da própria linguagem. Antes, eu não lia livros sobre C ++, e apenas três ou quatro anos atrás comecei a ler livros apenas em C ++, apenas para sentir a linguagem. Eu programei, mas não tinha uma abordagem sistemática e formal e fiquei impressionado com sua complexidade, o número de coisas que você pode arruinar se não escrever tudo corretamente.
Há alguns meses, ocorreu um erro no Unity, alguém cometeu um erro em um pedaço de código C ++, foi no construtor, algo foi passado por valor e, como resultado, pegamos o endereço desse valor e procuramos no cache. De fato, nos referimos a um valor que não estava mais na memória. E tudo isso porque os indicadores estavam confusos com os não indicadores, e quem fez essa refatoração não verificou todos os locais de uso. Um código completamente diferente que funcionou perfeitamente de repente parou de funcionar. Parece ser um pequeno erro, mas quebrou tudo. De fato, isso é um erro ao trabalhar com a memória. Então, sim, quando vejo essas coisas, estou convencido de que devemos restringir o acesso ao trabalho em C e C ++ e minimizar seu uso. Na parte .NET, eu realmente limitei o uso deles apenas a coisas específicas da plataforma. Mas escrever tudo em C # é bastante sombrio. Para acessar a API, você precisa fazer um monte de dlopen. Embora, por exemplo, você possa tentar encapsular tudo isso em um wrapper em C e organizar o acesso por apenas uma função. Prefiro isolar essas coisas e desenvolvê-las ainda mais em C e C ++. Mas esse é um tópico tão restrito sobre interoperabilidade e, em seguida, você fica com uma linguagem controlada normal, usa-a na maior parte do tempo e desfruta de uma compilação mais rápida.
Eu odeio os erros do compilador e vinculador C ++, odeio a necessidade de trabalhar com plataformas diferentes, tudo isso é muito, muito difícil. Você começa a compilar no MSVC, depois deve mudar para Clang e depois para o GCC. No Linux, no Mac, no Windows, no Android, no iOS e assim por diante. Trabalhar com C ++ é um pesadelo!
Eu odeio a separação entre arquivos no editor, arquivos .h e arquivos cpp. As pessoas estão completamente confusas na linguagem e começam a programar em macros. Eu amo metaprogramação, mas no C ++ moderno podemos fazer apenas uma loucura completa. Sozinhas, essas coisas são incríveis, mas na verdade já é demais.
Para resumir: sim, acho que podemos desenvolver software eficaz em C #. Talvez não tão rápido quanto em C ++, mas podemos. É exatamente isso que estamos tentando fazer no Unity - por exemplo, estamos fazendo um compilador de explosão para compilar um subconjunto específico de C #, obtendo desempenho máximo, ainda mais em locais do que seria possível em C ++ -, mas permanecendo em C #. É completamente seguro. Para ponteiros, você precisa declarar inseguro, não lançar exceções, fazer tudo explicitamente. E esta é uma experiência amarga. Ainda assim, você pode escrever um código que seja tão rápido quanto em C ++. Acho que é exatamente nessa direção que o .NET vale a pena ir e para onde devemos ir.
R.: Se falamos de código-fonte aberto, por exemplo, temos um coletor de lixo no .NET Core, que é um arquivo C muito grande e assustador. Dois megabytes de lixo, provavelmente gerados a partir de algum tipo de cisco (quase tantas cartas valiam a pena escrever manualmente). Talvez faça sentido reescrever tudo aqui em C #?Sim Converso com pessoas que trabalham no JIT na Microsoft e na comunidade. Há algo em que realmente acredito. Acredito que há um momento em que sua linguagem se torna mais madura e fundamental, e então você precisa desafiá-la, testá-la quanto à força. Você precisa poder usá-lo como base. Prove que você pode usá-lo para criar algo muito exigente no desempenho. E esta é a história do Garbage Collector e JIT. Uma porcentagem muito, muito grande de subsistemas de tempo de execução .NET, incluindo JIT e GC, pode ser feita em C #. Se você estabelecer uma regra de que em C ++ é possível descrever apenas abstrações da plataforma base, isso tornará a maior parte da plataforma de tempo de execução independente. Eu ficaria muito feliz se isso acontecesse. Mas este é um trabalho enorme.
Há uma razão pela qual eu gosto especialmente dessa idéia.
Eu já falei sobre isso, refatorar e melhorar a base de código em C / C ++ é tão complicado que, em algum momento, você para de fazer essa refatoração. Dói tanto que você simplesmente não toca mais. Você precisará transferir e alterar alguns arquivos manualmente, porque a refatoração no IDE funcionará mal, por exemplo, porque há muitos modelos - e assim por diante. Ao desenvolver em C #, você pode ser mais ambicioso quanto aos seus desejos. Adicionar novas otimizações seria possível muito mais rápido e fácil, simplesmente porque o tempo de compilação diminuiu. Tempo de iteração reduzido para testes e assim por diante. É bom que, por exemplo, no CoreRT, eles tentem usar o C # o máximo possível, em vez do C ++. A situação está mudando., .NET GC C#. . , , .NET GC, -. GC, , - GC. Java- Jikes RVM — Java. , Golang C, Golang. Golang-, , . , , , . , . LLVM, .NET JIT.
, , .
.: , . — . , AST- . Golang , . , ? ?, , ! , . : . : -, .
: , , , , . , : « ! !». . , .
LLVM, — , . , , , , , . . , , . , . , , , , ? , , , . , - : «, , , - » — , , , .
, . , , , , , , - . , : , , . , , . , , . , . , — .
— . -. , -, API, . . , SharpDX . . , , , . DirectX C++ API, C++. , . , - , . : , . , SharpDX. , PR, . pull request ( ). - . - , SharpDX - . : « ?» ( , ) , . 90- — . , , .
, , , , : , , .
.: — , ? . , , ?, — , SIMD. , , SIMD , . ( LLVM, , ). , , . , , , . - , . , . . - Intel LLVM. , , LLVM. , , . LLVM — , , , .NET. SIMD, CPU — . , , .NET — SIMD- . , , .
: « ». . . LLVM : -, , . , , Roslyn C#, . , , . , , , . SIMD — . GPU, CPU, — . 6, 8, 16, 42 . - , , .
.: Markdown Markdig, ? , Markdown? , ?, Markdown — , . , , Word - . . ? , , . . , RFC — , , , . , , . , ASCII-art. Word, PDF . Word. - — . , . Markdown, , - — , HTML. , . HTML, Markdown . , Github, Markdown- . . — . , Microsoft Markdown, GitHub, PR — , .
Markdown, CommonMark, , Markdown. , CommonMark — . , , . ,
Github CommonMark . — . . Microsoft CommonMark, Markdig. , Markdig , Markdown-, . , , , CommonMark, Markdig. , . Markdig , , , . , Microsoft .
.: , ? ?, . — , . . , . , , , . , . « , , ». , ? , , , , , - . , Google « X» « ». , — . , , , . , , - — , . « , - ?»
, , . . , , . , - . , , , . — , , ? , ? , .
, . . ? ? , , . , … - , . . , , , .
. . ! , . — . , — - . , , , . , , , . , . , . . , - : « !». -, , , . , . .
Esta é uma história sobre como se desenvolver, fazer o maior número possível de perguntas, tentar se abrir para as pessoas que você conhece, sobre eventos que você pode usar e participar de algo mais do que nós mesmos.
Na próxima sexta-feira, Alexandra fará uma apresentação “Atrás do compilador de rajada, convertendo o .NET IL em código nativo altamente otimizado usando LLVM” no DotNext 2018 Moscow . A conferência será realizada de 22 a 23 de novembro em Moscou e, ao que parece, será o maior DotNext de todos. Nós diríamos a você o que mais esperar da conferência, mas foi melhor para nós por seu outro orador, Dylan Beatty - ele gravou a música inteira: