2015-05-09 7 views
2

Я пытаюсь имитировать кучу задач, которые все вместе относятся к одному и тому же родовому проекту.
Задачи имеют длительность и приоритет (представлены списком задач, которые необходимо выполнить перед текущей задачей).Как моделировать приоритет задач?

Например:

 /--->A --->B\ 
Start ---->C------->End 
     \--->D---->E/ 

Это означает, что задачи А, С и D могут быть выполнены одновременно, но задача Б должна быть выполнена после того, как задача А, а задача Е после задачи Д.

Я написал этот код:

#!/usr/bin/python2.7 
# -*- coding: utf-8 -*- 
import simpy 


class Task(object): 
    """ 
     Has an id i.e.: 'E', 
     duration i.e.: 5 
     a list with Task that precede the current 
    """ 
    def __init__(self, idTask, duration, env, previousTasks=None): 
     self.idTask = idTask 
     self.duration = duration 
     self.env = envs 
     self.completed = env.event() 
     self.action = env.process(self.run()) 
     if previousTasks is None: 
      self.previousTasks = [] 
     else: 
      self.previousTasks = previousTasks 

    def run(self): 
     while self.can_execute() and not self.completed.triggered: 
      print "Starting task %s at time %s" % (self.idTask, self.env.now) 
      yield self.env.timeout(self.duration) 
      print "Completed task %s in time %s" % (self.idTask, self.env.now) 
      self.completed.succeed(True) 

    def can_execute(self): 
     result = True 
     for task in self.previousTasks: 
      if not task.completed.triggered: 
       result = False 
       break 
     return result 

if __name__ == "__main__": 
    env = simpy.Environment() 
    taskA = Task('A', 4, env) 
    taskB = Task('B', 5, env, [taskA]) 
    env.run(until=20) 

завершена атрибут в объект Task, это за то, что способ узнать, если текущая задача завершена или закончена. (Я пытался сделать это с помощью логического значения без каких-либо результатов).

taskB имеет taskA как задачу прецедента. Это означает, что taskB должен начаться до завершения Таски, но это выход, когда я запускаю его:

% python tasks.py 
Starting task A at time 0 
Completed task A at time 4 
% 

Я не понимаю, почему taskB не мог бежать.

---------------------------------------------- -----------------------------

решаемые

Я использовал "start_delayed" метод, доступный в simpy.util модуль от Simpy. В зависимости от того, выполняется ли текущая задача для выполнения предыдущих задач, «действие» каждой задачи - это простой процесс или отложенный процесс.
Задержка для каждой задачи вычисляется в add_precedences и evaluation_delays, но необходима для суммирования продолжительности предыдущих задач с предыдущей задачей текущего.
Вот окончательный код:

#!/usr/bin/python2.7 
# -*- coding: utf-8 -*- 
import simpy 
from simpy.util import start_delayed 

delays = {} 
completed = [] 


class Task(object): 
    """ Has an id i.e.: 'E', 
     duration i.e.: 5 
     a list with Task that precede the current 
    """ 
    def __init__(self, id, duration, env, previousTasks=None): 
     self.id = id 
     self.duration = duration 
     self.env = env 
     if previousTasks is None: 
      self.previousTasks = [] 
     else: 
      self.previousTasks = previousTasks 
     self.action = None 

    def run(self): 
     while True: 
      if delays[self.id] == self.env.now: 
       print "Start task: %s at time: %s" % (self.id, self.env.now) 
       yield self.env.timeout(self.duration) 
       completed.append(self.id) 
       print "Finish task: %s at time: %s" % (self.id, self.env.now) 
      else: 
       if self.id in completed: 
        self.env.exit() 


def add_precedences(prevTask, durations): 
    if len(prevTask) == 0: 
     return 0 
    else: 
     durations.extend(map(lambda x: x.duration, prevTask)) 
     for prev in prevTask: 
      add_precedences(prev.previousTasks, durations) 
     return sum(durations) 


def estimate_delays(tasks): 
    result = {} 
    for task in tasks: 
     durations = [] 
     total = (add_precedences(task.previousTasks, durations)) 
     result.update({task.id: total}) 
    return result 


def set_action(tasks): 
    for task in tasks: 
     if delays[task.id] > 0: 
      task.action = start_delayed(task.env, task.run(), delays[task.id]) 
     else: 
      task.action = env.process(task.run()) 

if __name__ == '__main__': 
    env = simpy.Environment() 
    taskA = Task('A', 4, env) 
    taskB = Task('B', 5, env, previousTasks=[taskA]) 
    taskC = Task('C', 2, env, previousTasks=[taskB]) 
    tasks = [taskA, taskB, taskC] 
    delays.update(estimate_delays(tasks)) 
    set_action(tasks) 
    env.run(until=20) 

В этом случае проект имеет 3 задачи ('A', 'B', 'C') и вот дерево:

Start --->A--->B--->C--->End 

B должен начинаться со временем: 4 (потому что это продолжительность A). И C, должен начинаться со временем: 9 (потому что это продолжительность B + A).
Чтобы узнать, какая задача уже завершена, я создал список, в котором каждая задача добавляет свой собственный идентификатор. Если его собственный идентификатор находится в этом списке, каждая задача удаляется из среды.

+0

Небольшой комментарий к вашему коду: вы не должны использовать [изменяемые аргументы по умолчанию] (http://stackoverflow.com/questions/1132941/least-astonishment-in-python-the-mutable-default- аргумент), они могут привести к неожиданностям. Чаще всего используется что-то вроде 'def __init __ (..., previousTasks = None): если previousTasks - None: previousTasks = []'. –

+0

Вы правы, я отредактирую это прямо сейчас, спасибо! – pazitos10

ответ

1

Я должен сделать это как комментарий, но у меня нет такой репутации. Тем не менее, я думаю, это может помочь с вашей проблемой.

Я не знаком с Simpy но вы можете быть запутанным вызвал и обрабатываются, не позволяющая задача B выполнить; проверьте эту ссылку: http://simpy.readthedocs.org/en/latest/api_reference/simpy.events.html#module-simpy.events

+0

Привет!Я попробовал использовать «self.completed.processed» вместо запуска, но это показывает мне следующее: RuntimeError: объект уже запущен. Но прежде, симуляция бросает, что работает только taskA. – pazitos10

+1

Хорошо. Кажется, я понял это сейчас. Когда задача B входит в функцию run, она не может выполняться, поскольку A является предшественником, поэтому она существует и никогда не возвращается к ней. Может быть, вы должны, но замкнутый цикл, внешний по отношению к тому, который находится в функции run (что было бы не очень эффективным). Идеальный способ, похоже, пытается сигнализировать задачу B, с которой он может начать. Так понятно? – pbc1303

+0

Это именно то, что происходит, потому что я попытался использовать класс Event для завершенного атрибута. Но я не могу сигнализировать о другой задаче с помощью Simpy, и если бы я мог, у меня должна была быть запись максимальной продолжительности предшественников и разбудить ее, когда env.now == timeToWake. Правильно? – pazitos10