Simuler des processus réels avec Python – Real Python

By | mars 25, 2020

Expert Python

Le monde réel regorge de systèmes, comme les aéroports et les autoroutes, qui connaissent fréquemment des encombrements et des retards. Lorsque ces systèmes ne sont pas optimisés, leur inefficacité peut conduire à d'innombrables clients mécontents et des heures de temps perdu. Dans ce didacticiel, vous allez apprendre à utiliser les simpy cadre pour créer des simulations virtuelles qui vous aideront à résoudre des problèmes comme ceux-ci.

Dans ce didacticiel, vous allez apprendre à:

  • Utilisation une simulation pour modéliser un processus réel
  • Créer un algorithme pas à pas pour approximer un système complexe
  • Conception et exécutez une simulation du monde réel en Python avec simpy

Dans ce didacticiel, vous allez créer une simulation pour une salle de cinéma locale. Votre objectif est de fournir au gestionnaire un script pour aider à trouver le nombre optimal d'employés à avoir sur le personnel. Vous pouvez télécharger le code source de ce script en cliquant sur le lien ci-dessous:

Qu'est-ce que la simulation

UNE simulation est une représentation d'un système du monde réel. On peut utiliser des modèles mathématiques ou informatiques de ce système pour étudier son fonctionnement ou ce qui se passe lorsque des parties de celui-ci sont modifiées. Les simulations sont utilisées dans les aéroports, les restaurants, les mécaniciens, les agences gouvernementales et de nombreux autres systèmes où une mauvaise allocation des ressources peut entraîner des encombrements, l'insatisfaction des clients et des retards de transport critiques.

UNE système peut être n'importe quel environnement où les choses se produisent. Des exemples de systèmes réels incluent les lave-autos, les banques, les usines de fabrication, les aéroports, les bureaux de poste, les centres d'appels, etc. Ces systèmes ont agents qui subissent processus en eux. Par exemple:

  • Un lave-auto fera passer les voitures par le processus de lavage.
  • Un aéroport fera passer les passagers par le processus de contrôle de sécurité.
  • Un centre d'appels permettra aux clients de passer par le processus de parler avec un télévendeur.

Cette relation est résumée dans le tableau ci-dessous:

Système Agent Processus
Lave-Auto Voiture Laver
Aéroport Passager Vérification de sécurité
Centre d'appel Client Parlez à un télévendeur

Comprendre les processus que traversent les agents au sein d'un système est un élément important de la planification logistique, en particulier pour les grandes organisations. Par exemple, un aéroport peut voir les temps d'attente des passagers à un poste de contrôle de sécurité monter en flèche s'il n'y a pas assez de travailleurs ce jour-là. De même, le courrier sensible au facteur temps peut être retardé de plusieurs jours (voire plusieurs semaines) s'il n'est pas correctement acheminé.

Ces cas de congestion peuvent avoir conséquences réelles temps et argent, il est donc important de pouvoir modéliser ces processus au préalable. Cela vous donne une idée de l'endroit où le système peut rencontrer des problèmes et comment les ressources doivent être allouées à l'avance pour résoudre ces problèmes de la manière la plus efficace possible.

Fonctionnement de la simulation

En Python, vous pouvez utiliser le simpy cadre pour la simulation d'événements. Tout d'abord, jetez un coup d'œil à la façon dont un processus simulé s'exécuterait en Python. Voici un extrait de code d'une simulation d'un système de points de contrôle de sécurité. Les trois lignes de code suivantes configurent l'environnement, transmettent toutes les fonctions nécessaires et exécutent la simulation:

# Configurer l'environnement
env = simpy.Environnement()

# Supposons que vous avez défini checkpoint_run () au préalable
env.processus(checkpoint_run(env, num_booths, check_time, passager_arrivée))

# Allons-y!
env.courir(jusqu'à=dix)

La première ligne de code ci-dessus établit le environnement. Pour ce faire, vous attribuez simpy.Environment () à la variable souhaitée. Ici, c'est simplement nommé env. Cela raconte simpy pour créer un objet d'environnement nommé env qui va gérer le temps de simulation et déplacer la simulation à travers chaque pas de temps suivant.

Une fois votre environnement établi, vous passerez toutes les variables qui vous serviront de paramètres. Ce sont les choses que vous pouvez modifier pour voir comment le système réagira aux changements. Pour ce système de points de contrôle de sécurité, vous utilisez les paramètres suivants:

  1. env: l'objet environnement pour planifier et traiter des événements
  2. num_booths: le nombre de cabines de contrôle d'identité
  3. check_time: le temps qu'il faut pour vérifier l'identité d'un passager
  4. passager_arrivée: la vitesse à laquelle les passagers arrivent à la file d'attente

Ensuite, il est temps de lancer la simulation! Vous pouvez le faire en appelant env.run () et en spécifiant la durée pendant laquelle la simulation doit s'exécuter. La simulation s'exécute en quelques minutes, donc cet exemple de code exécutera la simulation pendant 10 minutes en temps réel.

Pour récapituler, voici les trois étapes pour exécuter une simulation en Python:

  1. Établir l'environnement.
  2. Passer dans les paramètres.
  3. Courir la simulation.

Mais il se passe beaucoup plus de choses sous le capot! Vous devrez comprendre comment choisir ces paramètres et définir toutes les fonctions qui seront appelées lors de l'exécution de la simulation.

Commençons!

Comment débuter avec simpy

Il y a quelques tâches à faire que vous devriez vérifier dans votre liste avant de créer des simulations en Python. La première chose que vous devez faire est de vous assurer que vous avez une bonne compréhension des bases de Python. En particulier, vous devrez avoir une bonne compréhension des classes et des générateurs.

La prochaine chose que vous voudrez faire est d'installer le package requis. Le cadre principal que vous utiliserez est simpy. Il s'agit du package de base qui va créer, gérer et exécuter votre simulation. Vous pouvez l'installer avec pépin:

$ python3 -m pip install simpy

Vous aurez également besoin de quelques modules Python intégrés. Vous utiliserez le statistiques module pour calculer les temps d'attente moyens et la Aléatoire module pour générer des nombres aléatoires. Celles-ci font partie de la bibliothèque standard Python, vous n'avez donc pas besoin d'installer quoi que ce soit de nouveau.

Enfin, vous devrez choisir la manière dont vous souhaitez exécuter votre simulation. En général, vous pouvez choisir l'une des deux options:

  1. Exécutez-le de manière interactive: Utilisez un bloc-notes Jupyter, où chaque bloc de code contiendra sa propre définition de classe ou de fonction. La sortie sera affichée en bas de l'ordinateur portable.
  2. Exécutez-le dans le shell: Enregistrez votre simulation en tant que .py fichier et dites à Python de l'exécuter dans votre terminal. La sortie sera imprimée directement sur la console.

Choisissez la méthode qui vous convient le mieux! Le résultat devrait être le même.

Tout au long de ce didacticiel, vous verrez des références à un fichier autonome nommé simulate.py. Au fur et à mesure que vous parcourez ce didacticiel, les blocs de code feront référence simulate.py pour vous aider à garder une trace de la façon dont toutes les pièces s'assemblent. Pour votre référence, vous pouvez accéder au code complet de simulate.py sur le lien ci-dessous:

N'hésitez pas à enregistrer le fichier simulate.py et suivez dans votre éditeur préféré!

Comment simuler avec le simpy Paquet

La première étape pour exécuter une simulation dans simpy est de choisir un processus à modéliser. La simulation consiste à créer un environnement virtuel pour refléter un système du monde réel. Dans le même esprit, vous "simulez" une situation pour votre simulation!

Imaginez que vous avez été embauché pour aider le directeur d’un petit cinéma local. Le théâtre a reçu de mauvaises critiques en raison de leur longs temps d'attente. Le manager, qui se préoccupe autant des coûts que de la satisfaction des clients, ne peut que se permettre de garder autant d'employés.

Le manager est particulièrement inquiet de ce que le chaos peut se dérouler une fois que ces superproductions commencent à sortir: des lignes qui tournent autour du théâtre, des employés tendus à leur limite, des cinéphiles en colère qui manquent les scènes d'ouverture… C'est définitivement une situation à éviter!

Après avoir vérifié les critiques, le directeur a pu déterminer qu'un cinéphile donné de son théâtre était prêt à passer au plus 10 minutes entre son arrivée et le moment où il mettait ses fesses dans un siège. En d'autres termes, le temps d'attente moyen pour une nuit au théâtre doit être de 10 minutes ou moins. Le gestionnaire a demandé votre aide pour trouver une solution pour réduire les temps d'attente des clients en vertu de cette exigence de 10 minutes.

Remue-méninges sur un algorithme de simulation

Avant d'écrire une seule ligne de code, il est important que vous commenciez par comprendre comment votre processus se déroulerait dans la vie réelle. Il s'agit de s'assurer que, lorsque vous le transmettez à la machine, le processus reflète fidèlement ce que les clients vont vraiment vivre. Voici comment vous pourriez réfléchir aux étapes qu'un cinéphile pourrait suivre pour écrire votre algorithme:

  1. Arrivée au théâtre, faites la queue et attendez pour acheter un billet.
  2. Acheter un ticket à la billetterie.
  3. Attendez en ligne pour faire vérifier le billet.
  4. Avoir le ticket vérifié par un huissier.
  5. Choisir l'opportunité ou non de se mettre en ligne pour le stand de concession:
    • S'ils s'alignent, puis ils achètent de la nourriture.
    • S'ils ne font pas la queue, puis ils passent à la dernière étape.
  6. Aller trouver leur siège.

Il s'agit d'une itération étape par étape pour un cinéphile qui achète son billet à la billetterie du théâtre. Vous pouvez déjà voir quelles parties de ce processus peuvent être contrôlées. Vous pouvez affecter la durée d'attente d'un client en ayant plus de caissiers disponibles à la billetterie.

Certaines parties du processus ne peuvent pas être contrôlées, comme la toute première étape. Vous ne pouvez pas contrôler le nombre de clients qui arriveront ni la vitesse à laquelle ils le feront. Vous pouvez faire une supposition, mais vous ne pouvez pas simplement choisir un nombre, car ce serait un mauvais reflet de la réalité. Pour ce paramètre, la meilleure chose à faire est de utiliser les données disponibles pour déterminer une heure d'arrivée appropriée.

Avec ces choses à l'esprit, il est temps de construire votre simulation!

Configuration de l'environnement

Avant de commencer à créer votre simulation, vous devez vous assurer que votre environnement de développement est correctement configuré. La toute première chose que vous voudrez faire est d'importer les packages nécessaires. Vous pouvez le faire en déclarant importation déclarations en haut de votre fichier:

importation simpy
importation Aléatoire
importation statistiques

Ce sont les principales bibliothèques que vous utiliserez pour créer un script pour le directeur du théâtre. N'oubliez pas que l'objectif est de trouver le nombre optimal d'employés qui donne un temps d'attente moyen de moins de 10 minutes. Pour ce faire, vous devez collecter le temps qu'il faut à chaque cinéphile pour se rendre à son siège. L'étape suivante consiste à déclarer une liste pour contenir ces heures:

Cette liste contiendra le temps total que chaque cinéphile passe à se déplacer dans le théâtre, de son arrivée à son siège. Vous déclarez cette liste tout en haut du fichier afin de pouvoir l'utiliser dans n'importe quelle fonction que vous définissez ultérieurement.

Création de l'environnement: définition de classe

La première partie de la simulation que vous souhaitez créer est le plan du système. Ce sera l'environnement global dans lequel les choses se produisent, et les personnes ou les objets se déplacent d'un endroit à un autre. Rappelez-vous, un environnement peut être l'un des nombreux systèmes différents, comme une banque, un lave-auto ou un point de contrôle de sécurité. Dans ce cas, l'environnement est une salle de cinéma, ce sera donc le nom de votre classe:

classe Théâtre(objet):
    def __init__(soi):
        # Plus à venir!

Il est maintenant temps de réfléchir aux parties d'un cinéma. Bien sûr, il y a le théâtre lui-même, ce que vous avez appelé votre environnement. Plus tard, vous déclarerez explicitement le théâtre comme un véritable environnement en utilisant l'un des simpy les fonctions. Pour l'instant, appelez-le env pour faire court et l'ajouter à la définition de classe:

classe Théâtre(objet):
    def __init__(soi, env):
        soi.env = env

D'accord, quoi d'autre pourrait-il y avoir dans un théâtre? Vous pouvez le comprendre en réfléchissant à l'algorithme de simulation que vous avez planifié précédemment. Lorsqu'un cinéphile arrive, il devra faire la queue au box-office, où un caissier attendra pour l'aider. Vous venez de découvrir deux choses sur l'environnement du théâtre:

  1. Il y a caissiers.
  2. Les cinéphiles peuvent acheter des billets d'eux.

Les caissiers sont Ressource que le théâtre met à la disposition de ses clients, et ils aident les cinéphiles à travers le processus d'acheter un billet. Pour le moment, vous ne savez pas combien de caissiers sont disponibles dans le théâtre simulé. En fait, c'est le problème que vous essayez de résoudre. Comment les temps d'attente varient-ils en fonction du nombre de caissiers travaillant une nuit donnée?

Vous pouvez continuer et appeler cette variable inconnue num_cashiers. La valeur exacte que prendra cette variable peut être triée ultérieurement. Pour l'instant, sachez simplement que c'est un élément indispensable de l'environnement théâtral. Ajoutez-le à la définition de classe:

classe Théâtre(objet):
    def __init__(soi, env, num_cashiers):
        soi.env = env
        soi.la caissière = simpy.Ressource(env, num_cashiers)

Ici, vous ajoutez le nouveau paramètre num_cashiers à ton __init __ () définition. Ensuite, vous créez une ressource self.cashier et utilise simpy.Resource () pour déclarer combien il peut y avoir à tout moment dans cet environnement.

Il vous reste une étape à franchir. Un caissier ne va pas acheter un billet pour se, droite? Ils vont aider le cinéphile! Encore une fois, vous savez que ce processus d'achat d'un billet va prendre un certain temps. Mais combien de temps?

Supposons que vous ayez demandé au responsable des données historiques sur le théâtre, telles que les évaluations des performances des employés ou les reçus d'achat de billets. Sur la base de ces données, vous avez appris qu'il faut en moyenne entre 1 et 2 minutes pour émettre un ticket à la billetterie. Comment obtenez-vous simpy imiter ce comportement? Il ne prend qu'une seule ligne de code:

rendement soi.env.temps libre(Aléatoire.randint(1, 3))

env.timeout () raconte simpy pour déclencher un événement après un certain temps. Dans ce cas, l'événement est qu'un billet a été acheté.

Le temps que cela prend peut être une minute, deux minutes ou trois minutes. Vous voulez que chaque cinéphile passe un temps différent à la caisse. Pour ce faire, vous utilisez random.randint () pour choisir un nombre aléatoire entre les valeurs basses et hautes données. Ensuite, pour chaque cinéphile, la simulation attendra la durée choisie.

Terminons cela dans une fonction bien rangée et ajoutons-le à la définition de classe:

classe Théâtre(objet):
    def __init__(soi, env, num_cashiers):
        soi.env = env
        soi.la caissière = simpy.Ressource(env, num_cashiers)

    def ticket_achat(soi, amateur de cinéma):
        rendement soi.env.temps libre(Aléatoire.randint(1, 3))

Celui qui a déclenché l'événement Purchase_ticket () est le amateur de cinéma, ils doivent donc être passés comme argument requis.

C'est ça! Vous avez sélectionné une ressource limitée dans le temps, défini son processus associé et codifié cela dans votre définition de classe. Pour ce didacticiel, vous devez déclarer deux autres ressources:

  1. Huissiers pour vérifier les billets
  2. Les serveurs vendre de la nourriture

Après avoir vérifié les données envoyées par le gestionnaire, vous déterminez que les serveurs prennent entre 1 et 5 minutes pour terminer une commande. De plus, les huissiers sont remarquablement rapides à vérifier les billets, avec une vitesse moyenne de 3 secondes!

Vous devrez ajouter ces ressources à votre classe et définir les fonctions correspondantes check_ticket () et vendre de la nourriture(). Pouvez-vous comprendre à quoi devrait ressembler le code? Lorsque vous avez une idée, vous pouvez développer le bloc de code ci-dessous pour vérifier votre compréhension:

classe Théâtre(objet):
    def __init__(soi, env, num_cashiers, num_servers, num_ushers):
        soi.env = env
        soi.la caissière = simpy.Ressource(env, num_cashiers)
        soi.serveur = simpy.Ressource(env, num_servers)
        soi.huissier = simpy.Ressource(env, num_ushers)

    def ticket_achat(soi, amateur de cinéma):
        rendement soi.env.temps libre(Aléatoire.randint(1, 3))

    def check_ticket(soi, amateur de cinéma):
        rendement soi.env.temps libre(3 / 60)

    def vendre de la nourriture(soi, amateur de cinéma):
        rendement soi.env.temps libre(Aléatoire.randint(1, 5))

Examinez de près les nouvelles ressources et fonctions. Remarquez comment ils suivent le même format que celui décrit ci-dessus. vendre de la nourriture() les usages random.randint () pour générer un nombre aléatoire entre 1 et 5 minutes, représentant le temps qu'il faudrait à un cinéphile pour passer une commande et recevoir sa nourriture.

Le délai pour check_ticket () est un peu différent car les huissiers ne prennent que 3 secondes. Puisque simpy fonctionne en quelques minutes, cette valeur doit être transmise en fraction de minute, ou 3/60.

Se déplacer dans l'environnement: définition de la fonction

D'accord, vous avez configuré l'environnement en définissant une classe. Vous avez des ressources et des processus. Maintenant, vous avez besoin d'un amateur de cinéma pour les utiliser. Lorsqu'un amateur de cinéma arrive au théâtre, ils vont demander une ressource, attendre la fin de son processus, puis partir. Vous allez créer une fonction, appelée aller au cinéma(), pour garder une trace de ceci:

def aller au cinéma(env, amateur de cinéma, théâtre):
    # Moviegoer arrive au théâtre
    heure d'arrivée = env.maintenant

Trois arguments sont passés à cette fonction:

  1. env: le amateur de cinéma sera contrôlé par l'environnement, vous passerez donc ceci comme premier argument.
  2. amateur de cinéma: Cette variable suit chaque personne qui se déplace dans le système.
  3. théâtre: Ce paramètre vous donne accès aux processus que vous avez définis dans la définition de classe globale.

Vous déclarez également une variable heure d'arrivée de tenir l'heure à laquelle chaque amateur de cinéma arrive au théâtre. Vous pouvez obtenir cette fois en utilisant le simpy appeler pour env.now.

Vous voudrez que chacun des processus de votre théâtre avoir correspondant demandes dans aller au cinéma(). Par exemple, le premier processus de la classe est Purchase_ticket (), qui utilise un la caissière Ressource. le amateur de cinéma devra faire une demande au la caissière ressource pour les aider à travers le Purchase_ticket () processus. Voici un tableau pour résumer ceci:

Processus en théâtre Demande en aller au cinéma()
Purchase_ticket () Demandez un la caissière
check_ticket () Demandez un huissier
vendre de la nourriture() Demandez un serveur

Le caissier est une ressource partagée, ce qui signifie que de nombreux cinéphiles utiliseront le même caissier. Cependant, un caissier ne peut aider qu'un seul cinéphile à la fois. Vous devrez donc inclure un comportement d'attente dans votre code. Voici comment cela fonctionne:

def aller au cinéma(env, amateur de cinéma, théâtre):
    # Moviegoer arrive au théâtre
    heure d'arrivée = env.maintenant

    avec théâtre.la caissière.demande() comme demande:
        rendement demande
        rendement env.processus(théâtre.ticket_achat(amateur de cinéma))

Voici comment ce code fonctionne:

  1. theatre.cashier.request (): amateur de cinéma génère une demande d'utilisation d'un la caissière.
  2. demande de rendement: amateur de cinéma attend un la caissière devenir disponible si tous sont en cours d'utilisation. Pour en savoir plus sur le rendement , consultez Comment utiliser les générateurs et le rendement en Python.
  3. yield env.process (): amateur de cinéma utilise un disponible la caissière pour terminer le processus donné. Dans ce cas, c'est pour acheter un billet avec un appel à theatre.purchase_ticket ().

Une fois qu'une ressource est utilisée, elle doit être libérée pour que le prochain agent puisse l'utiliser. Vous pouvez le faire explicitement avec Libération(), mais dans le code ci-dessus, vous utilisez un avec à la place. Ce raccourci indique à la simulation de libérer automatiquement la ressource une fois le processus terminé. En d'autres termes, une fois le billet acheté, le amateur de cinéma partira et le caissier sera automatiquement prêt à prendre le prochain client.

Lorsqu'un caissier est libéré, le amateur de cinéma passera un certain temps à acheter leur billet. env.process () indique à la simulation d’aller au Théâtre par exemple et exécutez la Purchase_ticket () processus sur ce amateur de cinéma. le amateur de cinéma va répéter cela demande, utilisation, libération cycle pour faire vérifier son ticket:

def aller au cinéma(env, amateur de cinéma, théâtre):
    # Moviegoer arrive au théâtre
    heure d'arrivée = env.maintenant

    avec théâtre.la caissière.demande() comme demande:
        rendement demande
        rendement env.processus(théâtre.ticket_achat(amateur de cinéma))

    avec théâtre.huissier.demande() comme demande:
        rendement demande
        rendement env.processus(théâtre.check_ticket(amateur de cinéma))

Ici, la structure du code est la même.

Ensuite, il y a l'étape facultative d'acheter de la nourriture au stand de concession. Vous ne pouvez pas savoir si un cinéphile voudra acheter des collations et des boissons. Une façon de faire face à cette incertitude consiste à introduire un peu de hasard à la fonction.

Chaque amateur de cinéma voudra ou ne voudra pas acheter de la nourriture, que vous pouvez stocker comme valeurs booléennes Vrai ou Faux. Ensuite, utilisez le Aléatoire module pour que la simulation décide au hasard si oui ou non cette particulier amateur de cinéma va se rendre au stand de concession:

def aller au cinéma(env, amateur de cinéma, théâtre):
    # Moviegoer arrive au théâtre
    heure d'arrivée = env.maintenant

    avec théâtre.la caissière.demande() comme demande:
        rendement demande
        rendement env.processus(théâtre.ticket_achat(amateur de cinéma))

    avec théâtre.huissier.demande() comme demande:
        rendement demande
        rendement env.processus(théâtre.check_ticket(amateur de cinéma))

    si Aléatoire.choix([[[[Vrai, Faux]):
        avec théâtre.serveur.demande() comme demande:
            rendement demande
            rendement env.processus(théâtre.vendre de la nourriture(amateur de cinéma))

Cette déclaration conditionnelle renverra l'un des deux résultats suivants:

  1. Vrai: le amateur de cinéma demandera un serveur et commandera de la nourriture.
  2. Faux: le amateur de cinéma ira à la place pour trouver leurs sièges sans acheter de collations.

Maintenant, rappelez-vous que le but de cette simulation est de déterminer le nombre de caissiers, d'huissiers et de serveurs qui devraient être sur le personnel pour maintenir les temps d'attente sous 10 minutes. Pour ce faire, vous devez savoir combien de temps il a fallu amateur de cinéma pour se rendre à leurs sièges. Tu utilises env.now au début de la fonction pour suivre la heure d'arrivée, et encore une fois à la fin de chaque amateur de cinéma est terminé avec tous les processus et se dirige vers le théâtre:

def aller au cinéma(env, amateur de cinéma, théâtre):
    # Moviegoer arrive au théâtre
    heure d'arrivée = env.maintenant

    avec théâtre.la caissière.demande() comme demande:
        rendement demande
        rendement env.processus(théâtre.ticket_achat(amateur de cinéma))

    avec théâtre.huissier.demande() comme demande:
        rendement demande
        rendement env.processus(théâtre.check_ticket(amateur de cinéma))

    si Aléatoire.choix([[[[Vrai, Faux]):
        avec théâtre.serveur.demande() comme demande:
            rendement demande
            rendement env.processus(théâtre.vendre de la nourriture(amateur de cinéma))

    # Moviegoer entre dans le théâtre
    temps d'attente.ajouter(env.maintenant - heure d'arrivée)

Tu utilises env.now pour obtenir l'heure à laquelle le amateur de cinéma a terminé tous les processus et a atteint ses sièges. Vous soustrayez le cinéphile heure d'arrivée à partir de cette heure de départ et ajouter le décalage horaire résultant à votre liste d'attente, temps d'attente.

Cette amateur de cinéma est prêt à regarder quelques aperçus!

Faire bouger les choses: définition de la fonction

Vous devez maintenant définir une fonction pour exécuter la simulation. run_theater () sera chargé de créer une instance de théâtre et de générer des cinéphiles jusqu'à la fin de la simulation. La première chose que cette fonction devrait faire est de créer une instance de théâtre:

def run_theater(env, num_cashiers, num_servers, num_ushers):
    théâtre = Théâtre(env, num_cashiers, num_servers, num_ushers)

Comme il s'agit du processus principal, vous devrez passer toutes les inconnues que vous avez déclarées jusqu'à présent:

  • num_cashiers
  • num_servers
  • num_ushers

Ce sont toutes des variables dont la simulation a besoin pour créer et contrôler l'environnement, il est donc absolument vital de les transmettre toutes. Ensuite, vous définissez une variable théâtre et dites à la simulation d'installer le théâtre avec un certain nombre de caissiers, de serveurs et d'huissiers.

Vous pouvez également commencer votre simulation avec quelques cinéphiles en attente au théâtre. Il y aura probablement quelques personnes prêtes à partir dès l'ouverture des portes! Le manager dit de s'attendre à environ 3 cinéphiles en ligne prêts à acheter des billets dès l'ouverture du box-office. Vous pouvez dire à la simulation d'avancer et de parcourir ce groupe initial comme suit:

def run_theater(env, num_cashiers, num_servers, num_ushers):
    théâtre = Théâtre(env, num_cashiers, num_servers, num_ushers)

    pour amateur de cinéma dans intervalle(3):
        env.processus(aller au cinéma(env, amateur de cinéma, théâtre))

Tu utilises intervalle() pour peupler le théâtre avec 3 cinéphiles. Ensuite, vous utilisez env.process () pour dire à la simulation de se préparer à les déplacer dans le théâtre. Les autres cinéphiles arriveront au théâtre à leur rythme. Ainsi, la fonction devrait continuer d'envoyer de nouveaux clients dans le théâtre tant que la simulation est en cours.

Vous ne savez pas combien de temps il faudra aux nouveaux cinéphiles pour arriver au cinéma, alors vous décidez de regarder les données passées. En utilisant des reçus horodatés du box-office, vous apprenez que les cinéphiles ont tendance à arriver au théâtre, en moyenne, toutes les 12 secondes. Maintenant, tout ce que vous avez à faire est de dire à la fonction d'attendre aussi longtemps avant de générer une nouvelle personne:

def run_theater(env, num_cashiers, num_servers, num_ushers):
    théâtre = Théâtre(env, num_cashiers, num_servers, num_ushers)

    pour amateur de cinéma dans intervalle(3):
        env.processus(aller au cinéma(env, amateur de cinéma, théâtre))

    tandis que Vrai:
        rendement env.temps libre(0,20)  # Attendez un peu avant de générer une nouvelle personne

        # Presque fini!...

Notez que vous utilisez le nombre décimal 0,20 pour représenter 12 secondes. Pour obtenir ce nombre, vous divisez simplement 12 secondes par 60 secondes, ce qui correspond au nombre de secondes en une minute.

Après avoir attendu, la fonction doit incrémenter amateur de cinéma par 1 et générer la personne suivante. La fonction de générateur est la même que celle utilisée pour initialiser les 3 premiers cinéphiles:

def run_theater(env, num_cashiers, num_servers, num_ushers):
    théâtre = Théâtre(env, num_cashiers, num_servers, num_ushers)

    pour amateur de cinéma dans intervalle(3):
        env.processus(aller au cinéma(env, amateur de cinéma, théâtre))

    tandis que Vrai:
        rendement env.temps libre(0,20)  # Attendez un peu avant de générer une nouvelle personne

        amateur de cinéma + = 1
        env.processus(aller au cinéma(env, amateur de cinéma, théâtre))

C'est ça! Lorsque vous appelez cette fonction, la simulation générera 3 cinéphiles pour commencer et commencer à les déplacer à travers le théâtre avec aller au cinéma(). Après cela, les nouveaux cinéphiles arriveront au théâtre avec un intervalle de 12 secondes et se déplaceront dans le théâtre à leur rythme.

Calcul du temps d'attente: définition de la fonction

À ce stade, vous devriez avoir une liste temps d'attente qui contient le temps total qu'il a fallu à chaque cinéphile pour se rendre à son siège. Vous allez maintenant vouloir définir une fonction pour aider à calculer le temps moyen amateur de cinéma passe du moment où ils arrivent au moment où ils finissent de vérifier leur billet. get_average_wait_time () fait juste ceci:

def get_average_wait_time(temps d'attente):
    attente moyenne = statistiques.signifier(temps d'attente)

Cette fonction prend votre temps d'attente liste comme argument et utilise statistics.mean () pour calculer le temps d'attente moyen.

Étant donné que vous créez un script qui sera utilisé par le directeur de la salle de cinéma, vous devez vous assurer que la sortie peut être lue facilement par l'utilisateur. Vous pouvez ajouter une fonction appelée Calculate_wait_time () pour faire ça:

def Calculate_wait_time(heure_arrivée, heures de départ):
    attente moyenne = statistiques.signifier(temps d'attente)
    # Assez imprimé les résultats
    minutes, frac_minutes = divmod(attente moyenne, 1)
    secondes = frac_minutes * 60
    revenir rond(minutes), rond(secondes)

La dernière partie de la fonction utilise divmod () pour renvoyer les résultats en minutes et secondes, afin que le gestionnaire puisse facilement comprendre la sortie du programme.

Choix des paramètres: définition de la fonction d'entrée utilisateur

Au fur et à mesure que vous avez construit ces fonctions, vous avez rencontré quelques variables qui n'ont pas été clairement définies:

  • num_cashiers
  • num_servers
  • num_ushers

Ces variables sont les paramètres que vous pouvez changement pour voir comment la simulation change. Si un film à succès a des clients alignés autour du bloc, combien de caissiers devraient travailler? Et si les gens volaient au box-office mais restaient coincés dans les concessions? Quelle valeur de num_servers aidera à faciliter le flux?

Celui qui utilise votre simulation doit pouvoir modifier les valeurs de ces paramètres pour essayer différents scénarios. À cette fin, vous allez créer une fonction d'aide pour obtenir ces valeurs de l'utilisateur:

def get_user_input():
    num_cashiers = contribution("Nombre de caisses travaillant:")
    num_servers = contribution("# D'entrée de serveurs fonctionnant:")
    num_ushers = contribution("Nombre d'huissiers travaillant:")
    params = [[[[num_cashiers, num_servers, num_ushers]
    si tout(str(je).isdigit() pour je dans params):  # Vérifier que l'entrée est valide
        params = [[[[int(X) pour X dans params]
    autre:
        impression(
            "Impossible d'analyser l'entrée. La simulation utilisera les valeurs par défaut:",
            " n1 caissier, 1 serveur, 1 huissier. ",
        )
        params = [[[[1, 1, 1]
    revenir params

Cette fonction appelle simplement Python contribution() pour récupérer les données de l'utilisateur. Étant donné que la saisie par l'utilisateur risque d'être désordonnée, vous pouvez inclure un sinon pour attraper tout ce qui n'est pas valide. Si l'utilisateur entre de mauvaises données, la simulation s'exécutera avec des valeurs par défaut.

Finalisation de la configuration: définition de la fonction principale

La dernière fonction que vous voudrez créer est principale(). Cela garantira que votre script s'exécute dans le bon ordre lorsque vous l'exécutez sur la ligne de commande. Vous pouvez en savoir plus sur principale() dans Définition des fonctions principales en Python. Voici ce que votre principale() devrait ressembler à:

def principale():
  # Installer
  Aléatoire.la graine(42)
  num_cashiers, num_servers, num_ushers = get_user_input()

  # Exécutez la simulation
  env = simpy.Environnement()
  env.processus(run_theater(env, num_cashiers, num_servers, num_ushers))
  env.courir(jusqu'à=90)

  # Voir les résultats
  min, secondes = get_average_wait_time(temps d'attente)
  impression(
      "Exécution de la simulation ...",
      F" nLe temps d'attente moyen est mins    minutes et secs    secondes. ",
  )

Voici comment principale() travaux:

  1. Installer votre environnement en déclarant une graine aléatoire. Cela garantit que votre sortie ressemblera à ce que vous voyez dans ce tutoriel.
  2. Requete l'utilisateur de votre programme pour une entrée.
  3. Créer l'environnement et l'enregistrer comme variable env, qui déplacera la simulation à chaque pas de temps.
  4. Dire simpy pour exécuter le processus run_theater (), qui crée l'environnement du théâtre et incite les cinéphiles à s'y déplacer.
  5. Déterminer combien de temps vous souhaitez que la simulation s'exécute. Par défaut, la simulation est configurée pour s'exécuter pendant 90 minutes.
  6. Boutique la sortie de get_average_wait_time () en deux variables, min et secondes.
  7. Utilisation impression() pour montrer les résultats à l'utilisateur.

Avec cela, la configuration est terminée!

Comment exécuter la simulation

Avec seulement quelques lignes de code supplémentaires, vous pourrez voir votre simulation prendre vie. Mais d'abord, voici un aperçu des fonctions et classes que vous avez définies jusqu'à présent:

  • Théâtre: Cette définition de classe sert de modèle pour l'environnement que vous souhaitez simuler. Il détermine certaines informations sur cet environnement, comme les types de ressources disponibles et les processus qui leur sont associés.

  • aller au cinéma(): Cette fonction fait des demandes explicites pour utiliser une ressource, passe par le processus associé, puis la libère au cinéphile suivant.

  • run_theater (): Cette fonction contrôle la simulation. Il utilise le Théâtre plan de classe pour créer une instance d'un théâtre, puis appelle aller au cinéma() pour générer et déplacer les gens à travers le théâtre.

  • get_average_wait_time (): Cette fonction trouve le temps moyen nécessaire pour amateur de cinéma pour traverser le théâtre.

  • Calculate_wait_time (): Cette fonction garantit que la sortie finale est facile à lire pour l'utilisateur.

  • get_user_input (): Cette fonction permet à l'utilisateur de définir certains paramètres, comme le nombre de caissiers disponibles.

  • principale(): Cette fonction garantit que votre script s'exécute correctement dans la ligne de commande.

Maintenant, il vous suffit de deux lignes de code supplémentaires pour appeler votre fonction principale:

si __Nom__ == '__principale__':
    principale()

Avec cela, votre script est prêt à fonctionner! Ouvrez votre terminal, accédez à l'endroit où vous avez stocké simulate.pyet exécutez la commande suivante:

$ python simulate.py
Nombre de caisses travaillant:

Vous serez invité à sélectionner les paramètres souhaités pour votre simulation. Voici à quoi ressemble la sortie avec les paramètres par défaut:

$ python simulate.py
Nombre de caisses travaillant: 1
Nombre de serveurs fonctionnant: 1
Nombre d'huissiers travaillant: 1
Exécution de la simulation ...
Le temps d'attente moyen est de 42 minutes et 53 secondes.

Whoa! C’est long à attendre!

Quand changer les choses

N'oubliez pas que votre objectif est d'approcher le responsable avec une solution pour le nombre d'employés dont il aura besoin pour limiter les temps d'attente à moins de 10 minutes. À cette fin, vous voudrez jouer avec vos paramètres pour voir quels nombres offrent une solution optimale.

Tout d'abord, essayez quelque chose de complètement fou et maximisez les ressources! Disons qu'il y avait 100 caissiers, 100 serveurs et 100 huissiers travaillant dans ce théâtre. Bien sûr, cela est impossible, mais l'utilisation de chiffres incroyablement élevés vous indiquera rapidement quelle est la limite du système. Essayez-le maintenant:

$ python simulate.py
Nombre de caisses travaillant: 100
Nombre de serveurs en entrée: 100
Nombre d'huissiers travaillant: 100
Exécution de la simulation ...
Le temps d'attente moyen est de 3 minutes et 29 secondes.

Même si vous maximisez les ressources, vous n'obtiendrez que des temps d'attente de 3 minutes et demie. Maintenant, essayez de changer les chiffres pour voir si vous pouvez réduire les temps d'attente à 10 minutes, comme le gestionnaire l'a demandé. Quelle solution avez-vous trouvée? Vous pouvez développer le bloc de code ci-dessous pour voir une solution possible:

$ python simulate.py
Nombre de caisses travaillant: 9
Nombre de serveurs en entrée: 6
Nombre d'huissiers travaillant: 1
Exécution de la simulation ...
Le temps d'attente moyen est de 9 minutes et 60 secondes.

À ce stade, vous présenteriez vos résultats au directeur et feriez une suggestion pour aider à améliorer le théâtre. For instance, to cut down on costs, he might want to install 10 ticket kiosks at the front of the theater instead of keeping 10 cashiers on hand each night.

Conclusion

In this tutorial, you’ve learned how to build and run a simulation in Python using the simpy framework. You’ve come to understand how systems have agents undergo processes, and how you can create virtual representations of those systems to fortify them against congestion and delay. While the type of simulation can vary, the overall execution is the same! You’ll be able to apply what you’ve learned here to a variety of different scenarios.

Now you can:

  • Brainstorm a simulation algorithm step by step
  • Créer a virtual environment in Python with simpy
  • Define functions that represent agents and processes
  • Changement parameters of your simulation to find the optimal solution

There’s so much you can do with simpy, so don’t let your exploration stop here. Take what you’ve learned and apply it to new scenarios. Your solutions could help save people valuable time and money, so dive in and see what other processes you can optimize! You can download the source code for the script you built in this tutorial by clicking on the link below: