Запись на консоль с использованием функции Task.Run()
Мой коллега нашел проблему с нашим кодом, и потребовалось некоторое время, чтобы выследить, что именно происходит, но это лучше всего продемонстрировать на этом простом примере:
// Fails
class Program
{
static void Main(string[] args)
{
Task.Run(() => Console.WriteLine("Hello World"));
Console.ReadKey();
}
}
// Works fine
class Program
{
static void Main(string[] args)
{
Console.Write(String.Empty);
Task.Run(() => Console.WriteLine("Hello World"));
Console.ReadKey();
}
}
Из-за того, что писать на консоль в любом месте из основного потока, это позволяет фоновому потоку также писать на консоль, но мы изо всех сил пытаемся понять, почему это происходит. Может ли кто-нибудь объяснить, что пишут на консоль из основного потока, что первый фрагмент не делает?
Ответы
Ответ 1
У меня есть подозрение, что происходит. То, что я наблюдал:
- Если вы делаете что-либо с выходом консоли перед запуском
ReadKey
, это нормально. Сюда входит выборка Console.Out
, но не ее использование
- Если вы положили задержку так, что вызов
Console.WriteLine
начинается до вызова Console.ReadKey
, это нормально (и вы можете иметь несколько вызовов WriteLine
, пока ReadKey
ожидает
Я подозреваю, что первая операция с использованием консоли получает блокировку для инициализации (чтобы избежать ее инициализации дважды) и что метод ReadKey
сохраняет фиксацию до тех пор, пока ключ не будет прочитан. Это наверняка объяснит каждую программу, которую я выполнил до сих пор.
Операции, выполняющие гипотетическую инициализацию, интересны, хотя чтение Console.Out
"исправляет" проблему, но чтение из Console.In
не делает.
Я подозреваю, что ReadKey
инициализирует вывод, потому что значение все еще эхом отдано на консоль... но я не хотел бы ругаться.
Интересно, что использование Console.ReadLine()
вместо Console.ReadKey()
не вызывает проблемы в первую очередь.
Ответ 2
Собственно, первый случай не подводит. "Hello World" появляется перед тем, как приложение завершится. Это классическое Состояние гонки. В первом случае Console.ReadKey()
из основного потока выполняет задачу, а во втором - выигрывает задача. К сожалению, я не могу сказать вам точно, почему запись пустой строки заставляет задачу побеждать.