Мисля че TPL (TaskFactory.Startnew) работи сходно сThreadPool.QueueUserWorkItem по отношение на това, че изчаква за нишка от thread pool-а.
Общо взето е така.
Доколкото прочетох изглежда, че async/await само „понякога“ създава нова нишка.
Всъщност, никога него прави. Ако искаш да ползваш много нишки, трябва сам да си го напишеш. Има метод Task.Run, който се ползва вместо Task.Factory.StartNew, и е вероятно най-честия начин за пускане на задача от thread pool-а.
Ако се работи с IO completion ports не трябва да се създава нишка, но иначе мисля че трябва.
Методи като Stream.ReadAsync ще създадат Task обвивка около IOCP (Stream-а има IOCP).
Можеш да създадеш не- I/O, не процесорни „задачи“. Прост пример е Task.Delay, който връща задача, която завършва след определено време.
Готиното на async/await е,че можеш да наредиш на опашка работа за thread pool-a(като Task.Run), да свършиш операции обвързани с I/O(като Stream.ReadAsync), и някаква друга операция (Task.Delay) и всички те са Task-ове!. Могат да се изчакват или да се ползват в комбинации като Task.WhenAll.
Всеки метод, който връща Task, може да се await-ва- не е задължително да е асинхронен. Task.Delay и операции,обвързани с I/O просто използват TaskCompletionSource да създават и завършват задачи- единственото, което се върши от thread pool-а е реалното завършване на задачата, когато се хвърли event-а.
Предполагам че не съм напълно наясно с FromCurrentSynchronizationContext. Все си мислех, че е нишката на потребителския интерфейс.
В повечето случаи SynchronizationContext.Current е в контекста на:
- UI, ако текущата нишка е за UI
- ASP.NET заявка, ако текущата нишка обслужва ASP.NET заявка
- thread pool в останалите случаи
Всяка нишка може да си зададе SynchronizationContext,така че може да има изключения.
Забележи, че Task awaiter-а по подразбиране ще зададе оставащото от async метода на текущия SynchronizationContext(ако не е null), иначе отива в текущия TaskScheduler. Това не е толкова важно засега, но за напред ще е важно различие.
Относно async/await:
http://blogs.msdn.com/b/pfxteam/archive/2012/04/12/10293335.aspx
Относно „конкурентност“ срещу „multithreading“. Бих казал, че async позволява конкурентност, която може да не е многонишкова. Лесно се ползва await Task.WhenAll или await Task.WhenAny за конкурентна обработка, и освен ако не използваш изрично thread pool-а(Task.Run или ConfigureAwait(false)), тогава ще имаш много конкурентни операции по едно и също време. В този случай се ползва терминът „еднонишкова конкуренция“, въпреки че в ASP.NET се оказваш с „безнишкова конкуренция“, което е готино.