Ответ 1
DoEvents() опасно. Но держу пари, ты каждый день делаешь много опасных вещей. Буквально вчера я запустил несколько взрывных устройств (будущие читатели: обратите внимание на оригинальную дату публикации относительно определенного американского праздника). С осторожностью мы иногда можем объяснить опасности. Конечно, это означает, что вы знаете и понимаете, в чем опасность:
Проблемы повторного входа. Здесь на самом деле есть две опасности:
- Часть проблемы здесь связана со стеком вызовов. Если вы вызываете .DoEvents() в цикле, который сам обрабатывает сообщения, использующие DoEvents() и т.д., Вы получаете довольно глубокий стек вызовов. Легко использовать DoEvents() и случайно заполнить ваш стек вызовов, что приводит к исключению Qaru. Если вы используете .DoEvents() только в одном или двух местах, вы, вероятно, в порядке. Если это первый инструмент, к которому вы обращаетесь, когда у вас есть длительный процесс, вы можете легко оказаться здесь в беде. Даже одно использование в неправильном месте может позволить пользователю вызвать исключение (иногда просто удерживая клавишу ввода), и это может быть проблемой безопасности.
- Иногда можно найти один и тот же метод в стеке вызовов дважды. Если вы не создали метод с учетом этого (подсказка: вы, вероятно, не сделали), тогда могут произойти плохие вещи. Если все, что передано методу, является типом значения, и нет никакой зависимости от вещей вне метода, вы можете быть в порядке. Но в противном случае вам нужно тщательно подумать о том, что произойдет, если весь ваш метод будет запущен снова, прежде чем вам вернется управление в точке, где вызывается .DoEvents(). Какие параметры или ресурсы вне вашего метода могут быть изменены, чего вы не ожидали? Меняет ли ваш метод какие-либо объекты, где оба экземпляра в стеке могут действовать на один и тот же объект?
Проблемы с производительностью. DoEvents() может создать иллюзию многопоточности, но это не реальное многопоточность. В этом есть как минимум три настоящие опасности:
- Когда вы вызываете DoEvents(), вы передаете управление существующим потоком обратно в насос сообщений. Насос сообщений может, в свою очередь, передать управление чему-то другому, и это может занять некоторое время. В результате ваша оригинальная операция может закончиться гораздо дольше, чем если бы она находилась в потоке сама по себе, который никогда не возвращает управление, определенно дольше, чем нужно.
- Дублирование работы. Поскольку можно обнаружить, что вы запускаете один и тот же метод дважды, и мы уже знаем, что этот метод дорогой/длительный (или вам вообще не понадобится DoEvents()), даже если вы учли все упомянутые внешние зависимости выше, поэтому нет побочных эффектов, вы все равно можете дублировать большую работу.
- Другая проблема - крайняя версия первой: потенциальная тупиковая ситуация. Если что-то еще в вашей программе зависит от завершения вашего процесса и будет блокироваться до тех пор, пока это не произойдет, и эта вещь вызывается насосом сообщений из DoEvents(), ваше приложение застрянет и перестанет отвечать на запросы. Это может показаться надуманным, но на практике это удивительно легко сделать случайно, а сбои очень трудно найти и отладить позже. Это является корнем некоторых зависших ситуаций приложения, которые вы, возможно, испытывали на своем компьютере.
Проблемы с юзабилити. Это побочные эффекты, возникающие из-за неправильного учета других опасностей. Здесь нет ничего нового, если вы правильно смотрите в других местах.
Если вы можете быть уверены, что учли все эти вещи, тогда продолжайте. Но на самом деле, если DoEvents() - первое место, куда вы обращаетесь для решения проблем с отзывчивостью и обновлением пользовательского интерфейса, вы, вероятно, неправильно учитываете все эти проблемы. Если это не первое место, которое вы смотрите, есть достаточно других вариантов, и я бы задал вопрос, как вы попали к DoEvents() вообще. Сегодня DoEvents() существует главным образом для совместимости со старым кодом, который появился раньше других надежных опций, где они доступны, и в качестве опоры для начинающих программистов, которые еще не приобрели достаточного опыта для ознакомления с другими опциями.
Реальность такова, что большую часть времени, по крайней мере в мире .Net, компонент BackgroundWorker почти так же прост, по крайней мере, если вы сделали это один или два раза, и он выполнит свою работу в безопасный способ. Совсем недавно шаблон асинхронного/ожидающего выполнения или использование Task
может быть гораздо более эффективным и безопасным, без необходимости углубляться в полноценный многопоточный код на вашем компьютере. своя.