Я думал, что вызов async-метода с использованием Task.Run не вызывает никаких взаимоблокировок. Но это так:Вызов метода асинхронного синхронного использования Task.Run завершается в тупике
async Task<string> GetIdAsync()
{
return Task.Run(() => IncInt64Async("id", 1L)).Result.ToString(); // Deadlock
}
async Task<Int64> IncInt64Async(string key, Int64 inc);
Я знаю, что должен использовать ожидание. Так это работает:
async Task<string> GetIdAsync()
{
return await IncInt64Async("id", 1L); // of course, no deadlock.
}
Но я просто пытаюсь понять, почему первая попытка вызывает затор. В моем понимании async, тупик происходит только тогда, когда метод async захватывает контекст синхронизации и пытается вернуться к контексту, пока контекст не может его разрешить.
Кроме того, GetIdAsync() вызывается внутри Task.Run(), так что это все равно работает без синхронизации контекста:
Task.Run(() => {
some code...
id = getIdAsync();
some code...
}
);
Так что я сошел с ума, и перепробовали все варианты, я мог думать о, но до сих пор все попытки вызывает тупики:
Task.Run(() => IncInt64Async("id", 1L).ConfigureAwait(false).GetAwaiter().GetResult()).ConfigureAwait(false).GetAwaiter().GetResult();
IncInt64Async("id", 1L).ConfigureAwait(false).GetAwaiter().GetResult();
Task.Run(() => IncInt64Async("id", 1L)).Result;
Task.Run(() => IncInt64Async("id", 1L)).ConfigureAwait(false).GetAwaiter().GetResult();
Task.Run(async() => await IncInt64Async("id", inc)).ConfigureAwait(false).GetAwaiter().GetResult();
Task.Run(() => { var task = IncInt64Async("id", inc); task.Wait(); return task.Result; }).Result;
КСТАТИ Внутри реализации IncInt64Async, он использует несколько ждать, не ConfigureAwait (ложь).
Что может быть причиной?
Реализация IncInt64Async():
async Task<Int64> IncInt64Async(string key, Int64 value)
{
Task task = null;
byte error = 1;
byte[] bytes = null;
lock (c.WriteLock)
{
c.Write(key, value);
_readTask = task = _readTask.ContinueWith(async o =>
{
if ((error = await c.ReadByteAsync()) == 0) // **BLOCKS HERE**
{
bytes = new byte[ 8 ];
await c.ReadAsync(bytes, 0, 8);
}
NumWaits--;
}).Unwrap();
}
if (task != null)
await task.AnyContext();
if (error != 0)
throw new InvalidOperationException();
return BitConverter.ToInt64(bytes, 0);
}
'с' является экземпляром TcpHandler.
Он в основном пишет над tcp и читает от tcp.
Я использую ContinueWith() для выравнивания показаний. Я пробовал пропустить TaskScheduler.Default для ContinueWith().
Откуда вы это называете? Приложение UI, приложение asp.net, консоль? – Evk
@Evk это из консольного приложения. Даже GetIdAsync() вызывается внутри Task.Run следующим образом: Task.Run (() => id = GetIdAsync(); ...) – wooohoh
Если это консольное приложение, то как оно фактически блокируется? Тупик с асинксом обычно происходит в приложениях с некоторым понятием потока «пользовательского интерфейса» или «запроса», а не в консольных приложениях. – Evk