2014-11-17 2 views
6

Мой друг был приглашен на собеседование для разработчика Java для реализации программы, которая получает задачи, которые являются в основном объектами, которые имеют «делать», метод и поле времени, которое представляет секунды (например, целое число). Программа должна выполнить метод «делать» задачи - через X секунд с момента поступления этой задачи в программу (где X - это время, определенное в этом объекте задачи как поле времени).реализовать «задачу на основе» программы на Java без использования часов

например, если программа получила задание, которое имеет метод «делать», который печатает «привет, я задача» и имеет поле времени, которое равно 20, а затем через 20 минут после того, как эта задача будет получена в программа - сообщение «привет, я задача» будет напечатано в консоли.

вы не можете использовать часы или таймеры, но у вас есть какой-то «сборщик планировщика», который запускается каждую секунду и может проверять состояние каждой из задач и выполнять их, если необходимо.

Я думал, что хорошим решением будет то, что планировщик вычитает один из каждого «заданного времени», и если это время будет равно 0, тогда планировщик выполнит его и удалит из списка задач. проблема заключается в том, что в случае длинного списка задач это может занять много времени и до тех пор, пока планировщик не завершит все задачи - время не будет точным.

Из того, что я понял, это вопрос моделирования, поэтому он может быть связан с некоторым шаблоном проектирования или чем-то подобным.

есть ли у кого-нибудь идеи, что будет хорошо необязательно решение этой проблемы? Спасибо, ребята ...

+1

Не уверен, что это стоит ответа, поэтому я прокомментирую. Если вы ищете шаблон, это, вероятно, шаблон наблюдателя. Задачами могут быть наблюдатели планировщика (наблюдаемые), при каждом уведомлении() вы вызываете обновление задач(), и задача увидит, что его личное время достигло 0, а затем запускает сообщение –

+5

Создайте свой собственный часы из «планировщика», с более высоким циклом для проверки каждой задачи. Удерживайте низкоуровневые задачи до минимума. Лучше установить время активации каждой задачи, когда оно загружено, а не обслуживать счетчик таймера. Таким образом, если есть какое-то отставание в обслуживании, вы не потеряете время. Затем не проверяйте на '==' время активации, установите флажок '<=' –

+0

. Я бы ввел задачу в список, в котором каждый элемент также содержит количество секунд до его запуска по сравнению с предыдущим задача. Планировщику необходимо обновить оставшиеся секунды первой задачи в списке. Когда он достигает нуля (или ниже), задача может выполняться и выходить из списка. Вставка задач должна быть отсортирована. Если задача вставляется куда угодно, но в конце, оставшиеся секунды следующей задачи должны быть обновлены соответственно. –

ответ

3

Если это был вопрос интервью, он, скорее всего, идет в направлении сортировки и структуры данных.

Прежде всего, абстрагироваться от целых часов и планировщика. Здесь не проблема. Он гасит каждый временной интервал (скажем второй), поэтому каждую секунду вам нужно будет выяснить, какие задачи выполнять.

Так что вам действительно нужна структура данных, где за x секунд вы могли узнать, какие задачи выполнить. Что еще тебе нужно? Проблема говорит «получение задач», поэтому вы должны также вставлять новые объекты в какой-то момент y. Также, вероятно, разумно удалять выполненные задачи. Затем я не думаю, что разумно проверять только на равенство t == x, так как может случиться, что выполнение tast занимает больше времени, чем временной интервал. Если выполняемые задачи удаляются при выполнении, то вы можете безопасно выполнить все задачи с помощью t <= x.

Подводя итог, необходимо следующие операции (я буду считать время, чтобы быть длинное целое):

  • insertTask(int time, Task t)
  • Collection<Task> getTasksScheduledBefore(int time)
  • removeTasksScheduledBefore(t)

, что должно одно использование для этого? Ответ на этот вопрос зависит от того, где у вас есть интервью. :)

Простейшим было бы использовать что-то вроде TreeMap>:

  • insertTask тривиальна с put
  • getTasksScheduledBefore - headMap(t).values()
  • removeTasksScheduledBefore - headMap(t).clear()

Если вы» опрос для Google и К °, тогда они, вероятно, придумают что-то, что заставит вас придумайте свои собственные структуры данных. Деревья здесь хорошие, но с некоторыми предположениями вы также можете делать трюки с массивами, связанными списками и так далее. Например, если вам нужно всего лишь запланировать один день вперед, то Set<Task>[86400] будет также в порядке. :)

С Google также следите за такими вещами, как переполнение целых чисел и т. Д. Возможно, вам понадобится использовать BigInteger s вместо long. Убедитесь, что вы проверяете свои предположения с интервьюером (например, это время действительно целое, как вы должны реагировать на недопустимые значения и т. Д.).

+0

Мне нравится дух этого ответа.Поздравляю вас за конкретный уход, который вы наблюдали, связанный с контекстом интервью. Технически, отслеживание минимума дерева было бы неплохо, если бы вы не подумали? – Rerito

+0

@Rerito спасибо. Я думаю, что 'SortedMap' имеет нечто вроде' firstKey() ', но я не думаю, что это полезно здесь. Я думаю, вам нужно будет запросить диапазон '<= t', а не только минимальное значение, так как может случиться, что несколько интервалов будут« пропущены »(слишком много задач для выполнения и т. Д.). Каковы были ваши мысли о минимуме дерева? Почему это было полезно? – lexicore

+1

Выполнение реальной быстрой проверки при запуске планировщика. Если текущее время меньше минимальной цели, нам нечего делать, и эта проверка равна O (1) – Rerito

2

Во-первых, сохраните время начала в переменной. При каждом тике планировщика увеличьте его на 1.

Когда запланирована новая задача, оберните ее в объект, в котором хранится задача, и галочка для ее выполнения (текущее время выполнения задачи). Поместите обертку в список и отсортируйте список по времени запуска (или сразу же поместите его в нужное место).

Затем, при каждом тике, вы должны проверить только первую задачу в списке, чтобы убедиться, что она должна быть выполнена. Если это так, проверьте следующий, иначе вы закончите.

Таким образом, для добавления новых задач требуется немного больше усилий, но вы минимизируете работу, необходимую для каждого тика планировщика (чаще всего это будет LOT).

+1

Приоритетные очереди кажутся подходящими для этой проблемы. Используя двоичную кучу (или k-ary все, что вам нравится), она должна работать как шарм. Разумеется, куча должна быть рассчитана таким образом, чтобы предотвратить нежелательное копирование + перераспределение – Rerito

1

Похоже, у меня была та же идея, что и Дэвид десять Хоув. Я использую карту todos с назначенным временем в качестве ключа, поэтому мне не нужно ее сортировать, просто проверьте, содержит ли оно текущее время.

currentCounter инициализируется 0 и увеличивается каждый раз (благодаря запланированному). Нам не нужно знать фактическое текущее время и тему упомянутого вопроса «без часов».

package org.conffusion.taskmgr; 

import java.util.ArrayList; 
import java.util.Collection; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 

public class Taskmanager { 

    /** 
    * map of scheduled tasks. For a single moment in time multiple tasks can be 
    * scheduled, so a Collection structure of Tasks is necessary. 
    */ 
    private Map<Long, Collection<Task>> todos = new HashMap<Long, Collection<Task>>(); 

    /** 
    * increased every second since the startup of the Manager 
    */ 
    private static long currentCounter = 0; 

    /** 
    * Use this method to add a new task to the manager. 
    * @param task 
    */ 
    public void addTask(Task task) { 
     long key=currentCounter + task.getDelay(); 
     if(todos.containsKey(key)) 
     { 
      // there is already a task for this time, so just add it to the existing list. 
      todos.get(key).add(task); 
     } else 
     { 
      List<Task> tasklist=new ArrayList<Task>(); 
      tasklist.add(task); 
      todos.put(key, tasklist); 
     } 
    } 

    /** 
    * called by the scheduler every second 
    */ 
    public void schedulerCallback() { 
     currentCounter++; 
     // Do we have tasks for the current time ? 
     if(todos.containsKey(currentCounter)) 
     { 
      // Loop over the scheduled tasks and execute them. 
      for(Task t:todos.get(currentCounter)) 
      { 
       // Run every task in a separate thread so our manager does not get blocked by the tasks. 
       new Thread(new TaskRunner(t)).start(); 
      } 
      // Clean up of launched tasks 
      todos.remove(currentCounter); 
     } 
    } 

    private class TaskRunner implements Runnable { 
     private Task task; 
     public TaskRunner(Task task) 
     { 
      this.task=task; 
     } 
     @Override 
     public void run() { 
      task.todo(); 
     } 
    } 
    /** 
    * Interface every Task must implement. 
    */ 
    public interface Task { 

     /** 
     * Delay in seconds to wait before todo() must be called. 
     * @return 
     */ 
     public long getDelay(); 

     public void todo(); 
    } 
} 
+0

Разница между вашим подходом и моим заключается в том, что вы помещаете todo на карту, а не в отсортированный список. Учитывая, что поиск по карте в Java является постоянным временем, это выглядит отлично для меня, хотя –

+0

Он работал бы, если заданные времена начала выражаются как тики _internal scheduler_. Хеш-таблица позволяет предотвратить использование отношения порядка на отметках времени. Таким образом, вам необходимо проверить __all__ ключи, которые вы зарегистрировали в своей таблице, на отметке _each_. Процесс обновления тика имеет решающее значение, он должен выполнять реальные быстрые – Rerito

+0

Rerito, когда задача добавляется на карту, ключ является текущимСоздание + задержка. Поэтому задача должна только указать количество секунд. F.E. currentCounter = 20, delay = 5 -> добавляется ключ = 25. В течение 5 тиков (секунд) текущее значение = 25, и задача будет найдена и выполнена. Хорошо, я действительно предполагаю, что внешний планировщик вызовет менеджера каждую секунду. Но здесь мы используем планировщик. – Conffusion