1. Да, задача может исполниться где угодно. Более того, вы не поверите, но некоторые таски вообще могут нигде не исполняться, т.к. исполнять нечего (см. п. 5). Таск - это прежде всего абстракция значения, которое будет получено в будущем, и для получения которого возможно нужно что-то посчитать или просто подождать. См.
futures and promises.
2. Ну не обязательно в новом потоке, может быть выполнится и в существующем потоке если в пуле потоков есть свободный.
3. Асинхронные операции ввода-вывода называются так потому, что выполняются через асинхронное API операционной системы. Нет никакого смысла использовать асинхронную операцию, но делать это в отдельном потоке созданном специально для этой операции. Потоки нужны прежде всего для того, чтобы эффективно нагружать исполнителей, т.е. процессоры (в том числе разные их ядра).
4. Можно в новом, можно в потоке из пула. Так или иначе, если операция предполагает именно расчёты, а не ожидание ввода/вывода, то безусловно это тот случай, когда имеет смысл переложить нагрузку на другой поток.
5. Если представлять таск как одну из сторон "трубы", по которой прилетит результат асинхронной операции, то Task - это принимающая сторона, а TaskCompletiotionSource - передающая (производящая результат) сторона. Когда вы создаёте таск из кода который нужно выполнить, этот код становится передающей стороной. Но Task абстрагирует любую асинхронную операцию, не только ту где нужно долго что-то считать. Возможно вам нужно дождаться одного байтика из сети, и операция будет считаться завершенной. Во всех тех случаях, когда вы хотите самостоятельно "произвести" результат для какого-то таска (а сам таск отдать "наружу" другому коду, например вернуть из функции), вы можете использовать TaskCompletionSource.
(Кстати, в C++ принимающая сторона называется
future, а передающая (производящая) -
promise. В JS принимающая сторона называется
Promise, а передатчиком является функтор).