Die Antwort ist eigentlich, dass sie könnten, aber es besteht der Wunsch, dies nicht zu tun.
Fasern werden verwendet, weil Sie damit steuern können, wie die Planung erfolgt. Dementsprechend ist es viel einfacher, einige Algorithmen unter Verwendung von Fasern zu entwerfen, da der Programmierer zu sagen hat, in welcher Faser zu einem bestimmten Zeitpunkt ausgeführt wird. Wenn Sie jedoch möchten, dass zwei Fasern gleichzeitig auf zwei verschiedenen Kernen ausgeführt werden, müssen Sie sie manuell planen.
Threads geben die Kontrolle darüber, welcher Code auf dem Betriebssystem ausgeführt wird. Im Gegenzug erledigt das Betriebssystem viele hässliche Aufgaben für Sie. Einige Algorithmen werden schwieriger, da der Programmierer weniger Einfluss darauf hat, welcher Code zu einem bestimmten Zeitpunkt ausgeführt wird, sodass unerwartetere Fälle auftreten können. Tools wie Mutexe und Semaphoren werden einem Betriebssystem hinzugefügt, um dem Programmierer gerade genug Kontrolle zu geben, um Threads nützlich zu machen und einen Teil der Unsicherheit zu beseitigen, ohne den Programmierer zu stören.
Dies führt zu etwas, das noch wichtiger ist als kooperativ oder präventiv: Fasern werden vom Programmierer gesteuert, während Threads vom Betriebssystem gesteuert werden.
Sie möchten keine Faser auf einem anderen Prozessor erzeugen müssen. Die Befehle auf Baugruppenebene sind dafür äußerst kompliziert und häufig prozessorspezifisch. Sie möchten nicht 15 verschiedene Versionen Ihres Codes schreiben müssen, um diese Prozessoren zu handhaben, also wenden Sie sich an das Betriebssystem. Die Aufgabe des Betriebssystems ist es, diese Unterschiede zu abstrahieren. Das Ergebnis ist "Threads".
Fasern laufen über Fäden. Sie rennen nicht alleine. Wenn Sie also zwei Fasern auf unterschiedlichen Kernen ausführen möchten, können Sie einfach zwei Threads erzeugen und auf jedem von ihnen eine Faser ausführen. In vielen Implementierungen von Fasern können Sie dies leicht tun. Der Mehrkernträger kommt nicht von den Fasern, sondern von den Gewinden.
Es wird leicht zu zeigen, dass Sie, wenn Sie keinen eigenen prozessorspezifischen Code schreiben möchten, nichts tun können, indem Sie mehreren Kernen Fasern zuweisen, was Sie nicht tun könnten, indem Sie Threads erstellen und jedem Fasern zuweisen. Eine meiner Lieblingsregeln für das API-Design lautet: "Eine API wird nicht erstellt, wenn Sie alles hinzugefügt haben, sondern wenn Sie nichts mehr zum Herausnehmen finden." Angesichts der Tatsache, dass Multi-Core perfekt verarbeitet wird, indem Fasern auf Threads gehostet werden, gibt es keinen Grund, die Faser-API durch Hinzufügen von Multi-Core auf dieser Ebene zu komplizieren.