8
Как все успеть?
Кви Ноа работает в Сент-Луисе, в фирме сельскохозяйственных технологий, которая специализируется на продаже генетически модифицированных семян. Она всего лишь скромная секретарша, и ее босс дал ей кучу заданий, которые нужно закончить к концу недели. Отчетный день – пятница. Осталось всего два дня. Если Кви не выполнит все задания вовремя, ей не разрешат пойти на ежегодный корпоратив в субботу. Этот банкет – единственное мероприятие в жизни фирмы, во время которого начальники и подчиненные общаются на равных. Для Кви это шанс «на людей посмотреть и себя показать». Если ей повезет, то она получит повышение, на которое так давно надеется. Что же ей делать?
Справляться с растущим потоком задач – одно из самых важных умений в жизни взрослого человека. Только подумайте, как много книг и статей вам нужно будет прочитать по теме эффективного планирования рабочего времени, чтобы умело распределять рабочую нагрузку. Кви хорошо знает, что успеть все вовремя – задача непростая, которая потребует напряжения всех сил. Давайте рассмотрим для нее несколько способов достичь цели.
ЦЕЛЬ: ВЫПОЛНИТЬ ВСЕ ЗАДАНИЯ К КОНЦУ НЕДЕЛИ.
МЕТОД 1: ПОРАБОТАТЬ НЕМНОГО НАД ОДНИМ ЗАДАНИЕМ. ПЕРЕКЛЮЧИТЬСЯ НА ДРУГОЕ. ПОРАБОТАТЬ НЕМНОГО. ПЕРЕКЛЮЧИТЬСЯ НА СЛЕДУЮЩЕЕ. И ТАК ДАЛЕЕ.
МЕТОД 2: ОТСОРТИРОВАТЬ ЗАДАНИЯ ОТ САМОГО ПРОСТОГО ДО САМОГО СЛОЖНОГО. НАЧАТЬ С ПРОСТОГО. КОГДА ОНО БУДЕТ СДЕЛАНО, ПЕРЕЙТИ КО ВТОРОМУ ПРОСТОМУ. И ТАК ДАЛЕЕ.
МЕТОД 3: РАССОРТИРОВАТЬ ЗАДАНИЯ ПО ПРИОРИТЕТНОСТИ. НАЧАТЬ С САМОГО ВАЖНОГО. КОГДА ОНО БУДЕТ ЗАКОНЧЕНО, ПЕРЕЙТИ К СЛЕДУЮЩЕМУ ПО ВАЖНОСТИ. И ТАК ДАЛЕЕ.
Все эти методы наверняка знакомы. Применяя метод 1, мы используем единицы времени, чтобы определять, когда переключиться с одного задания на другое. Например, у нас три набора заданий по трем различным предметам в школе, и все нужно сдать до конца недели. Можно посвятить утро одному предмету, день – второму, а вечером заняться третьим. На следующий день повторяем эту схему и так далее, пока не будут готовы все задания. Этот метод распределения времени – хороший пример того, как современные операционные системы справляются с многочисленными приложениями, и его иногда называют контекстным переключением. Диспетчер следит за текущими процессами,[33] отводит им определенное время, а потом контролирует, чтобы каждый процесс умещался в предписанный ему хронометраж.
Переключение между процессами происходит так плавно, что при наблюдении за операционной системой создается впечатление, будто они протекают параллельно. Сегодня при наличии многоядерных процессоров так оно и есть. Четырехъядерный процессор может одновременно вести четыре процесса, и контекстуальное переключение ему требуется только тогда, когда процессов запускается больше, чем у него ядер.
Это напоминает приложение параллельной обработки, которое имеет аналог в реальной жизни и называется конвейерной обработкой. Набор взаимосвязанных заданий распределяется и выполняется так, чтобы оптимизировать имеющиеся в наличии ресурсы. Например, вы с двумя вашими друзьями вдруг вспомнили, что забыли приготовить мешки с подарками для гостей, а вечеринка вот-вот закончится. Чтобы сделать как можно больше мешков в единицу времени, эффективно применить что-то вроде конвейерного метода: вы пишете поздравления на мешке, один друг складывает в него подарки, а второй – завязывает мешки лентой. Это лучше других подходов, когда один или оба ваших друга будут ждать, пока вы подпишете все мешки. Распределение заданий важно, но до определенной степени: как однажды написал Фред Брукс, девять женщин не родят ребенка за один месяц.
При современных характеристиках «железа» мы не замечаем границ возможностей контекстуального переключения. Между тем каждый раз, когда система его выполняет, ей нужно придержать состояние последнего процесса, очистить регистры и удалить передаваемые данные, а затем загрузить новое состояние процесса.[34]
Для человека когнитивная нагрузка, которая сопровождает этот тип переключения, может быть довольно серьезной. Одно из препятствий на пути обеспечения продуктивности – необходимость прервать текущее занятие, переключиться на что-то срочное, а затем вернуться к предыдущему делу. Операционная система работает подобным образом, запуская так называемый обработчик прерываний, который может временно остановить текущий процесс, чтобы либо передать ему некоторые данные, которых ждет система, либо изменить приоритетность задач.
Если время прерывания достаточно велико, мы можем побороться, приводя разум в состояние, необходимое для выполнения оригинального задания. Контекстное переключение имеет определенные преимущества – оно гарантирует, что мы поработаем по крайней мере над какой-то частью каждого задания. В то же время, когда задача имеет временные рамки, стратегия «Не пропускать ни одного задания» грозит разочарованием и переутомлением.
Метод 2 – это подход, знакомый многим любителям откладывать на потом. В соответствии с ним нужно оставлять сложные задачи под самый конец, а вначале делать только самое простое. Его преимущество в том, что он приносит множество небольших, но быстрых побед. Его часто называют жадным алгоритмом, но этот термин необязательно подразумевает пренебрежение какими-либо делами. Он просто подчеркивает, что алгоритм пытается достичь максимального результата за счет минимума усилий.
Удачное применение жадного алгоритма – найти самую быструю дорогу из одной точки в другую, например, между двумя городами. Мы спрашиваем себя в каждом пункте: «До какого города здесь ближе всего?» Это хороший способ принимать решения, хотя он может помешать вам увидеть оптимальные пути на ранних этапах путешествия. Мы уже встречали разновидность такого подхода в главе 4, хотя Иоаннис просто хотел выбраться из лабиринта и не задумывался, сколько времени у него это займет.
Об алгоритмах поиска кратчайшего пути написано много, и здесь есть несколько соперничающих друг с другом подходов. Один из самых известных называется алгоритмом Дейкстры. Он был создан в 1959 году голландским ученым-компьютерщиком Эдсгером В. Дейкстрой. В более общем виде этот класс алгоритмов известен как алгоритмы поиска по графу.
Другое применение жадных алгоритмов, которое стоит отметить, – это поиск потенциальных совпадений в массиве текста, часто с целью заменить совпавшие символы другими. Например, в тексте есть словосочетание «Джесса Джессика», и мы хотим унифицировать разные варианты написания этого имени. Команда «Искать сочетание «Джесс»», после которой стоит набор других букв, оканчивающийся на «а», даст нам все встречающиеся формы написания этого имени (Джесса Джессика), а не отдельные имена («Джесса», «Джессика»). Поисковик совпадений остановится на последней «а», а не на первой. Иногда это полезно, хоть в данном случае у нас другая цель поиска.
Представьте, что вы едете по незнакомой дороге и видите знак, который показывает, сколько километров до трех окрестных городов. Вы можете поддаться искушению и поехать в ближайший из них.
Нежадный алгоритм сложнее и часто приносит лучшие результаты. Можно увидеть его аналог в военных действиях, где быстрый успех, например защита столицы, приносится в жертву ради более важной победы. Вспомните, как русская армия обошлась с армией Наполеона в 1812 году.
Нежадный алгоритм может быть охарактеризован как длинная, или затянувшаяся, игра. Wall Street Journal недавно опубликовал статью о чемпионах по скрабблу из Нигерии. Их победа была обусловлена не обширным словарным запасом, а интуитивной практикой выбора более коротких слов. Вместо того чтобы подбирать семи- и восьмибуквенные слова, которые приносят больше очков, нигерийские игроки обнаружили, что игра четырех- и пятибуквенными словами приводит к улучшению стратегии в долгосрочной перспективе. Они сохраняли самые сочетаемые буквы для будущих раундов, когда им выпадали не лучшие варианты из мешка. Вот отрывок из статьи, рисующий преимущества такого подхода:
«Британцы лидируют со словом «утверждение», которое дало им 86 очков, но в следующие пять раундов им удавалось выбирать слова, которые приносили меньше 30 очков. После слова «анкета» (93) мистер Джигере вырвался вперед. В финале счет был 449 против 432. Члены команды-победительницы подняли своего чемпиона на руки и понесли по комнате под популярную нигерийскую песню «Мы победили».
Метод 3 устраняет один из недостатков метода 2, фокусируясь на задачах, которые действительно важны. Мы составляем список задач, событий или чего-либо еще и располагаем их по приоритету. Заметьте, что «приоритетность» бывает и функцией «времени завершения», поэтому можно сказать, что метод 2 также располагает задачи в соответствии с их приоритетом. Возьмем, к примеру, принтер. Если в очереди на печать стоит 10 документов по 50 страниц каждый, а за ними идет один одностраничный документ, то, возможно, для принтера имеет смысл поставить последнюю задачу в приоритет, а не заставлять ее ждать до самого конца печати. Разделение двух методов показывает, что приоритетность иногда базируется на других свойствах, а не только на времени выполнения.
Получая новое задание, мы можем поместить его не в конец списка, а куда-нибудь в середину – в зависимости от приоритетности. Включение нового пункта в середину списка приоритетных задач порой приводит к увеличению времени, пока вы стираете старые задачи, освобождая место под новые. В главе 12 мы поговорим о том, как компьютер выбирает способ хранения такого списка (который часто называют очередью с приоритетом), чтобы такие вставки совершались достаточно быстро. Часто в повседневной жизни этот алгоритм наиболее эффективен.
Вот как все три метода выглядят на графике:
При условии, что задачи не зависят друг от друга (то есть очередность выполнения более ранних заданий не связана с временем выполнения последующих задач), все три метода Кви займут одинаковое время.[35] Как было упомянуто в главе 1, мы сравниваем основные операции во всех трех методах, то есть оцениваем, сколько времени Кви тратит на работу над задачами. Если бы мы вместо этого рассматривали, скажем, время, которое уходит у Кви на составление и ведение ее списка задач, то мы бы сказали, что метод 1 занимает постоянное время, то есть 0, а метод 2 и метод 3 занимают в худшем случае логарифмический объем времени. Для чего концентрироваться на одном наборе опций и приносить в жертву другой? Возможно, потому первый набор больше способствует достижению итоговой цели по сравнению со вторым, поскольку составление и ведение списка заданий – не такое уж сложное дело.[36] Больше об этом будет рассказано в главах 10 и 12.
Недостаточно смотреть на относительные величины; когда речь идет о результате задания, все становится существенным. Это относится и к алгоритмам, исполняемым за постоянное время. Представьте работника парковки, который хочет впихнуть как можно больше машин в ряд, чтобы эффективнее использовать пространство. Все ваши алгоритмы по выезду с парковки могут быть таковыми, но уровень сервиса разительно отличается. Например, если не оставлять свободного проезда, то парковщику придется в худшем случае убрать восемь других машин, чтобы добраться до нужного авто. Если оставлять проезд свободным все время, то придется убирать максимум три машины. Введение временных ограничений на то, когда можно оставлять или забирать машины, с правилом «без привилегий на въезд и выезд» позволит вообще не убирать другие машины при возвращении авто клиенту.
Если Кви не удастся выполнить задание в полном объеме, то какой результат будет для нее вторым по значимости? Если она решит уделять больше внимания высокоприоритетным задачам, то вдруг первое же задание, за которое она возьмется, займет целую неделю? Можно ли это совместить?[37] Такие вопросы порой порождают творческие и оригинальные решения.
Отступление: в романе Кейго Хигашино «Страсть подозреваемого Х» (2005) учитель математики говорит о решении геометрической задачи путем превращения ее в алгебраическую, чтобы понять, как оценивают его студенты свои пробелы в знаниях. Это удивительное напоминание о том, насколько легко принимать прочитанное как данность, не оспаривая его. Мы интерпретируем новую информацию тем способом, который соответствует имеющимся у нас знаниям. Это явление ученый-компьютерщик Алан Кай назвал релятивизацией. Оно может стать и пороком, и добродетелью, в зависимости от того, как ее использовать.