我正在使用 Python 和Simpy进行模拟。在模拟中,作业由资源处理。一些工作需要单一资源,而另一些工作需要多个资源。我想一次检索(获取)多个资源,因此优先考虑需要较少资源的作业。
资源由FilterStore中的项目表示。
下面的示例解决方案利用 for 循环并保留资源。我正在寻找一种不保留资源,而是将资源分配给所有资源都可用的作业的解决方案。下面的例子被简化了,但我正在寻找一种解决方案,它允许我同时产生大量资源,类似于AllOf 事件。
我遇到了创建 FilterStore 对象的子类的建议,但我不知道该怎么做。我还遇到了一个使用 store 对象的子类的示例。有没有办法在不创建子类的情况下实现预期的行为?如果没有,如何创建 FilterStore 的子类?
代码:
import simpy
def source(env, jobs):
count = 0
for i in jobs:
env.process(job(env, count, i))
count += 1
yield env.timeout(1)
def job(env, count, resources_required):
resources_used = []
# the for loop yield (reserves) resources even if not all resources are available
print('job: {} requires resources: {} at time: {}'.format(count, resources_required, env.now))
for i in resources_required:
resource = yield resources.get(lambda resource: resource['id'] == i)
resources_used.append(resource)
print('job: {} retrieved resources: {} at time: {}'.format(count, resources_required, env.now))
yield env.timeout(4)
for i in resources_used:
yield resources.put(i)
print('job: {} released resources: {} completed at time: {}'.format(count, resources_required, env.now))
env = simpy.Environment()
resources = simpy.FilterStore(env, capacity=3)
for i in range(resources.capacity):
resources.put({'id': i})
jobs = [
[2],
[0],
[2, 0],
[2],
[2, 0]
]
env.process(source(env, jobs))
env.run(until=50)
输出:
job: 0 requires resources: [2] at time: 0
job: 0 retrieved resources: [2] at time: 0
job: 1 requires resources: [0] at time: 1
job: 1 retrieved resources: [0] at time: 1
job: 2 requires resources: [2, 0] at time: 2
job: 3 requires resources: [2] at time: 3
job: 4 requires resources: [2, 0] at time: 4
job: 0 released resources: [2] completed at time: 4
job: 1 released resources: [0] completed at time: 5
job: 2 retrieved resources: [2, 0] at time: 5
job: 3 retrieved resources: [2] at time: 9
job: 2 released resources: [2, 0] completed at time: 9
job: 3 released resources: [2] completed at time: 13
job: 4 retrieved resources: [2, 0] at time: 13
job: 4 released resources: [2, 0] completed at time: 17
在示例中,这意味着作业 3 的优先级应高于作业 2。在时间 4,作业 3 所需的所有资源都可用。但是,作业 2 在时间 2 保留了资源 (2) 之一,并在作业 3 之前启动。
工作顺序:
current sequence: [0, 1, 2, 3, 4]
desired sequence: [0, 1, 3, 2, 4]
更新:
下面的代码采用了稍微不同的方法。它避免了FilterStore。相反,它利用字典中的 id 包含的多个 Store。id 可以在两个商店中找到正确的资源。当时为了从两个不同的商店中提取两个资源,我使用了以下语句:'yield env.all_of'。不过,顺序并不如预期。资源似乎被保留了。
Code:
import simpy
import random
import collections
def source(env, jobs):
count = 0
for i in jobs:
env.process(job(env, count, i))
count += 1
yield env.timeout(1)
def job(env, count, resources_required):
resources_used = []
#resources_required = random.sample(range(0, 5), random.randint(1, 5))
# the for loop yield (reserves) resources even if not all resources are available
print('job: {} requires resources: {} at time: {}'.format(count, resources_required, env.now))
resources_needed = []
for i in resources_required:
for j in resources:
if i == j['id']:
resources_needed.append(j['store'].get())
yield env.all_of(resources_needed)
print('job: {} retrieved resources: {} at time: {}'.format(count, resources_required, env.now))
yield env.timeout(4)
for i in resources_needed:
i.resource.put(i)
print('job: {} released resources: {} completed at time: {}'.format(count, resources_required, env.now))
sequence.append(count)
env = simpy.Environment()
resources = []
capacity = 1
for i in range(5):
resource = collections.OrderedDict()
store = simpy.Store(env, capacity=capacity)
for j in range(capacity):
item = {'resource_id': i,
'item_id': j
}
store.put(item)
resource = {'id': i,
'store': store
}
resources.append(resource)
jobs = [
[2],
[0],
[2, 0],
[2],
[2, 0]
]
sequence = []
random.seed(1234567890)
env.process(source(env, jobs))
env.run(until=50)
print('...')
print('current sequence: {}'.format(sequence))
print('desired sequence: [0, 1, 3, 2, 4]')
结果:
job: 0 requires resources: [2] at time: 0
job: 0 retrieved resources: [2] at time: 0
job: 1 requires resources: [0] at time: 1
job: 1 retrieved resources: [0] at time: 1
job: 2 requires resources: [2, 0] at time: 2
job: 3 requires resources: [2] at time: 3
job: 0 released resources: [2] completed at time: 4
job: 4 requires resources: [2, 0] at time: 4
job: 1 released resources: [0] completed at time: 5
job: 2 retrieved resources: [2, 0] at time: 5
job: 2 released resources: [2, 0] completed at time: 9
job: 3 retrieved resources: [2] at time: 9
job: 3 released resources: [2] completed at time: 13
job: 4 retrieved resources: [2, 0] at time: 13
job: 4 released resources: [2, 0] completed at time: 17
工作顺序:
current sequence: [0, 1, 2, 3, 4]
desired sequence: [0, 1, 3, 2, 4]
更新 2:
下面的代码再次采用了稍微不同的方法。现在,使用 PriorityResource 代替存储。该资源再次包装在字典对象中。通过优先考虑需要较少资源的作业,可以获得所需的顺序(使用上面的作业列表)。但是,现在总是优先考虑较短的工作,这不是我的本意。所有资源都可用的作业应优先于某些资源可用的作业。我已经更改了下面的工作列表以反映问题。如果可以根据“未来”的时间对工作进行优先级排序,那么当工作的所有资源都可用时,这个问题就有可能得到解决。是否可以确定何时有资源可用?
代码:
import simpy
import random
def source(env, jobs):
count = 0
for i in jobs:
env.process(job(env, count, i))
yield env.timeout(1)
count += 1
def job(env, count, resources_required):
print('job: {} requires resources: {} at time: {}'.format(count, resources_required, env.now))
resources_needed = []
for i in resources_required:
for j in resources:
if i == j['id']:
resources_needed.append(j['resource'].request(priority=len(resources_required)))
yield env.all_of(resources_needed)
print('job: {} retrieved resources: {} at time: {}'.format(count, resources_required, env.now))
yield env.timeout(4)
for i in resources_needed:
i.resource.release(i)
print('job: {} released resources: {} completed at time: {}'.format(count, resources_required, env.now))
sequence.append(count)
env = simpy.Environment()
resources = []
capacity = 1
for i in range(5):
resource = {
'id': i,
'resource': simpy.PriorityResource(env, capacity=capacity)
}
resources.append(resource)
jobs = [
[2, 0],
[1],
[2, 0],
[2],
[2, 0]
]
sequence = []
random.seed(1234567890)
env.process(source(env, jobs))
env.run(until=50)
print('...')
print('current sequence: {}'.format(sequence))
print('desired sequence: [0, 1, 2, 3, 4]')
输出:
job: 0 requires resources: [2, 0] at time: 0
job: 0 retrieved resources: [2, 0] at time: 0
job: 1 requires resources: [1] at time: 1
job: 1 retrieved resources: [1] at time: 1
job: 2 requires resources: [2, 0] at time: 2
job: 3 requires resources: [2] at time: 3
job: 0 released resources: [2, 0] completed at time: 4
job: 4 requires resources: [2, 0] at time: 4
job: 3 retrieved resources: [2] at time: 4
job: 1 released resources: [1] completed at time: 5
job: 3 released resources: [2] completed at time: 8
job: 2 retrieved resources: [2, 0] at time: 8
job: 2 released resources: [2, 0] completed at time: 12
job: 4 retrieved resources: [2, 0] at time: 12
job: 4 released resources: [2, 0] completed at time: 16
工作顺序:
current sequence: [0, 1, 3, 2, 4]
desired sequence: [0, 1, 2, 3, 4]