Como mencionado em um comentário e sem ver nenhum de seu código ou outras informações (o que não seria aqui, de qualquer maneira), tudo o que posso dizer é que seu programa parece estar com o IO vinculado.
Os meios, enquanto seus cálculos podem usar mais da sua CPU, eles têm que esperar nos dados e gastar muitos ciclos de espera, em vez de calcular. Isso pode ser devido à maneira como você escreve código (otimização de loop, vetorização, etc). Um problema comum é acessar seus dados de uma maneira que cause muitos erros de cache. Seus múltiplos núcleos também podem compartilhar um cache L3 e, se todos eles estiverem trabalhando em dados diferentes, você provavelmente terá muitas falhas. Buscando memória da DRAM principal é ordens de magnitude mais lenta do que a memória cache on-die. Se seus dados vierem dos discos, você também terá que lidar com a latência de leitura de disco, além da latência de DRAM. Se os dados estiverem na rede ethernet ou em alguma outra interconexão, você também terá que considerar a latência nessas leituras. Você também pode incorrer em muita espera em gravações em disco, especialmente se estiver escrevendo com frequência em pequenos blocos, em vez de armazenar em buffer para gravações grandes.
Em suma, há muitas considerações de desempenho de IO que limitam sua capacidade de manter 100% de uso da CPU em seus núcleos. Minha recomendação é criar um perfil do seu código, descobrir suas limitações de IO e garantir que seu código seja eficiente e avance a partir daí.