{"id":2097,"date":"2016-03-31T17:01:47","date_gmt":"2016-03-31T21:01:47","guid":{"rendered":"http:\/\/bioinfo.iric.ca\/fr\/?p=2097"},"modified":"2017-04-29T17:05:58","modified_gmt":"2017-04-29T21:05:58","slug":"parallelise-ton-python-y","status":"publish","type":"post","link":"https:\/\/bioinfo.iric.ca\/fr\/parallelise-ton-python-y\/","title":{"rendered":"Parall\u00e9lise ton Python !"},"content":{"rendered":"<div class=\"fusion-fullwidth fullwidth-box fusion-builder-row-1 hundred-percent-fullwidth non-hundred-percent-height-scrolling\" style=\"--awb-border-radius-top-left:0px;--awb-border-radius-top-right:0px;--awb-border-radius-bottom-right:0px;--awb-border-radius-bottom-left:0px;--awb-overflow:visible;--awb-flex-wrap:wrap;\" ><div class=\"fusion-builder-row fusion-row\"><div class=\"fusion-layout-column fusion_builder_column fusion-builder-column-0 fusion_builder_column_1_1 1_1 fusion-one-full fusion-column-first fusion-column-last fusion-column-no-min-height\" style=\"--awb-bg-size:cover;--awb-margin-bottom:0px;\"><div class=\"fusion-column-wrapper fusion-flex-column-wrapper-legacy\"><div class=\"fusion-text fusion-text-1\"><p style=\"text-align: justify\">\n<\/div><div class=\"fusion-text fusion-text-2\"><div class=\"fusion-text fusion-text-2\"><\/div>\n<h3 style=\"text-align: justify\">Dans cet article, vous apprendrez ce qu&rsquo;est que le <em>multithread<\/em> ou multicore, et dans quel cas utiliser l\u2019un ou l\u2019autre.<\/h3>\n<p>Votre ami nerd vous parle de sa d\u00e9formation professionnelle tout le temps? \u00c0 vouloir parall\u00e9liser et optimiser son temps? Vous souhaitez vous aussi comprendre et gagner du temps en parall\u00e9lisant vos programmes en Python? Alors cet article est pour vous!<\/p>\n<p style=\"text-align: justify\">Vous allez pouvoir, gr\u00e2ce \u00e0 une petite dose de parall\u00e9lisme, de Python et de beaucoup d\u2019amour, gagner \u00e9norm\u00e9ment de temps. Le but \u00e9tant ici de raccourcir les pauses caf\u00e9 et de ne plus pouvoir regarder la Guerre des \u00e9toiles-\u00e9pisode IV directement sur le terminal :<\/p>\n<pre><code class=\"bash\">telnet towel.blinkenlights.nl<\/code><\/pre>\n<p>Mais vous apprendrez ici \u00e0 regarder Star Wars et coder tout en buvant un caf\u00e9 \ud83d\ude09<br \/>\nIl vous faut tout d\u2019abord un peu de vocabulaire. Si vous savez ce qu\u2019est la diff\u00e9rence entre le multiCoeur et le multiThread, vous pouvez passer directement \u00e0 la partie <strong>Python<\/strong>. Si vous savez programmer en Python vous pouvez passer directement \u00e0 la partie <strong>\u00ab\u00a0Module threading\u00a0\u00bb<\/strong>. Si vous savez d\u00e9j\u00e0 programmer en Python ET que vous maitrisez parfaitement le module threading alors vous pouvez soit : <strong>ne pas lire cet article<\/strong> et gagner 38 minutes (temps estim\u00e9 selon une \u00e9tude bidon) soit : <strong>lire cet article<\/strong> et passer un bon moment.<\/p>\n<ol style=\"text-align: justify\">\n<li style=\"text-align: justify\">\n<h3>MultiCoeur : Est-ce qu\u2019on parle ici de pieuvres?<\/h3>\n<p>Le terme \u2018coeur\u2019 ou <em>core<\/em> en anglais est mal choisi. Nous pr\u00e9f\u00e9rons l\u2019analogie avec le cerveau (vous me direz que la pieuvre a aussi plusieurs cerveaux). Votre ordinateur peut utiliser en m\u00eame temps (on dit en parall\u00e8le) plusieurs programmes ou applications (mail, navigateur web, &#8230;). Imaginez que vous ayez plusieurs cerveaux, alors vous pourriez lire cet article et faire une transformation de bact\u00e9ries en m\u00eame temps.<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"https:\/\/bioinfo.iric.ca\/wpbioinfo\/wp-content\/uploads\/2016\/03\/MC.png\" rel=\"attachment wp-att-2078\"><img decoding=\"async\" class=\" wp-image-2078 aligncenter\" src=\"https:\/\/bioinfo.iric.ca\/wpbioinfo\/wp-content\/uploads\/2016\/03\/MC-300x194.png\" alt=\"MC\" width=\"379\" height=\"245\" srcset=\"https:\/\/bioinfo.iric.ca\/wpbioinfo\/wp-content\/uploads\/2016\/03\/MC-300x194.png 300w, https:\/\/bioinfo.iric.ca\/wpbioinfo\/wp-content\/uploads\/2016\/03\/MC-768x496.png 768w, https:\/\/bioinfo.iric.ca\/wpbioinfo\/wp-content\/uploads\/2016\/03\/MC-1024x661.png 1024w, https:\/\/bioinfo.iric.ca\/wpbioinfo\/wp-content\/uploads\/2016\/03\/MC.png 1262w\" sizes=\"(max-width: 379px) 100vw, 379px\" \/><\/a><br \/>\nLe syst\u00e8me d&rsquo;exploitation qui peut \u00eatre vu comme l\u2019ordonnanceur, ex\u00e9cute les applications en les r\u00e9partissant entre les differents coeurs (CPU). L&rsquo;ordinateur peut alors diviser le travail entre chaque coeur et faire plusieurs choses en m\u00eame temps. Dans cette image, ce syst\u00e8me poss\u00e8de 2 coeurs, donc cet ordinateur peut utiliser les applications 1 et 2 en m\u00eame temps, par exemple \u00eatre sur internet et sur le terminal simultan\u00e9ment.<\/li>\n<li style=\"text-align: justify\">\n<h3>MultiThread : Est-ce que l\u2019on va parler ici de couture ?<\/h3>\n<p>Gr\u00e2ce au multithread, votre programme va pouvoir faire plusieurs t\u00e2ches en m\u00eame temps . Dans une application monothread, une t\u00e2che emp\u00eache les autres t\u00e2ches de s&rsquo;ex\u00e9cuter tant que cette premi\u00e8re n&rsquo;est pas termin\u00e9e!!!<br \/>\n\u00c0 l\u2019inverse, une application multithread optimise l&rsquo;efficacit\u00e9 de l&rsquo;unit\u00e9 centrale parce qu&rsquo;elle ne reste pas inactive et va s\u2019ex\u00e9cuter en parall\u00e8le.<br \/>\n<a href=\"https:\/\/bioinfo.iric.ca\/wpbioinfo\/wp-content\/uploads\/2016\/03\/MT.png\" rel=\"attachment wp-att-2079\"><img decoding=\"async\" class=\" wp-image-2079 aligncenter\" src=\"https:\/\/bioinfo.iric.ca\/wpbioinfo\/wp-content\/uploads\/2016\/03\/MT-300x218.png\" alt=\"MT\" width=\"380\" height=\"276\" srcset=\"https:\/\/bioinfo.iric.ca\/wpbioinfo\/wp-content\/uploads\/2016\/03\/MT-220x161.png 220w, https:\/\/bioinfo.iric.ca\/wpbioinfo\/wp-content\/uploads\/2016\/03\/MT-300x218.png 300w, https:\/\/bioinfo.iric.ca\/wpbioinfo\/wp-content\/uploads\/2016\/03\/MT-768x558.png 768w, https:\/\/bioinfo.iric.ca\/wpbioinfo\/wp-content\/uploads\/2016\/03\/MT-1024x744.png 1024w, https:\/\/bioinfo.iric.ca\/wpbioinfo\/wp-content\/uploads\/2016\/03\/MT.png 1293w\" sizes=\"(max-width: 380px) 100vw, 380px\" \/><\/a><br \/>\nIci, l\u2019application contient 3 t\u00e2ches qui vont \u00eatre lanc\u00e9es en parall\u00e8le et,donc, avancer en m\u00eame temps. Pour une m\u00eame utilisation du CPU, on va pouvoir lancer 3 t\u00e2ches \u00e0 la fois.<\/li>\n<li style=\"text-align: justify\">\n<h3>Rappel Python : Ah, les invertebr\u00e9s, \u00e7a me connait<\/h3>\n<p><em>\u00ab\u00a0Le terme <b>Python<\/b> est un nom vernaculaire ambigu d\u00e9signant en fran\u00e7ais plusieurs esp\u00e8ces de serpents appartenant \u00e0 diff\u00e9rents genres des familles des Pythonidae et des Loxocemidae. Pythonest le nom scientifique d&rsquo;un genre de serpents de la famille des Pythonidae.<\/em>\u00ab\u00a0<i> \u00a0&#8212; <\/i>Wikipedia<\/p>\n<p>Python est aussi un langage de programmation qui permet de faire des programmes cool pouvant \u00eatre parall\u00e9lis\u00e9s. On parle ici de programmes et non pas de scripts. Si vous souhaitez apprendre le Python, nous vous recommandons : <a href=\"http:\/\/inforef.be\/swi\/download\/apprendre_python3_5.pdf\" target=\"_blank\">ce super livre<\/a>.<\/li>\n<\/ol>\n<p style=\"text-align: justify\"><strong>C\u2019est bon, vous \u00eates fin pr\u00eats pour l\u2019aventure!!<\/strong><\/p>\n<p style=\"text-align: justify\">Commen\u00e7ons par regarder les diff\u00e9rences entre le mutilprocess et multithread au sein du m\u00eame module \u00ab\u00a0<strong>concurrent.futures<\/strong>\u00a0\u00bb qui permet de parall\u00e9liser tant en threads qu\u2019en processus.<\/p>\n<pre><code class=\"python\">from concurrent import futures<\/code><\/pre>\n<p style=\"text-align: justify\">Le code qui suit est tir\u00e9 du <a href=\"http:\/\/nathangrigg.net\/images\/2015\/futures.html\" target=\"_blank\">site<\/a> :<\/p>\n<p style=\"text-align: justify\">Il a \u00e9t\u00e9 l\u00e9g\u00e8rement modifi\u00e9 et comment\u00e9 pour une meilleure lecture. Les images qui suivent sont les images originales de l\u2019auteur.<\/p>\n<p style=\"text-align: justify\">L\u2019auteur sp\u00e9cifie 5 <strong>\u2018workers\u2019<\/strong>, donc 5 threads\/processus qui roulent en m\u00eame temps pour 15 <strong>\u00ab\u00a0it\u00e9rations\u00a0\u00bb<\/strong><code class=\"python\"> <\/code><\/p>\n<pre><code class=\"python\">WORKERS = 5\r\nITERATIONS = 15\r\n<\/code><\/pre>\n<p style=\"text-align: justify\">Voici la fonction utilis\u00e9e :<\/p>\n<pre><code class=\"python\">\r\ndef test_multithreading(executor, function):\r\n    start_time = datetime.datetime.now()\r\n    with executor(max_workers=WORKERS) as ex:\r\n        result = list(ex.map(function, itertools.repeat(start_time, iterations)))\r\n        \r\n    start, stop = np.array(result).T\r\n    return start, stop\r\n<\/code><\/pre>\n<p style=\"text-align: justify\">Pour une <strong>meilleure compr\u00e9hension<\/strong>, voici une deuxi\u00e8me version (moins jolie) de cette fonction qui fait la m\u00eame chose, mais qui est \u00e9crite avec des boucles <strong>\u00ab\u00a0for\u00a0\u00bb<\/strong>:<\/p>\n<pre><code class=\"python\">\r\ndef test_multithreading(executor, function):\r\n   start_time = [datetime.datetime.now() for _ in range(iterations)]\r\n\r\n   with executor(max_workers=WORKERS) as ex:\r\n       processes = []\r\n       for st_time in start_time:\r\n           processes.append(ex.submit(function, st_time))\r\n\r\n       result = []\r\n       for p in processes:\r\n           result.append(p.result())\r\n\r\n   start, stop = np.array(result).T\r\n   return start, stop\r\n<\/code><\/pre>\n<p style=\"text-align: justify\">Exemple d\u2019appel \u00e0 la fonction:<\/p>\n<pre><code class=\"python\">test_multithreading(futures.ThreadPoolExecutor, busy)<\/code><\/pre>\n<p style=\"text-align: justify\"><strong>\u00ab\u00a0busy\u00a0\u00bb<\/strong> \u00e9tant une fonction qu\u2019on d\u00e9finit ci-dessous.<\/p>\n<p style=\"text-align: justify\"><strong>\u00ab\u00a0Idle\u00a0\u00bb<\/strong> : Le programme effectue une pause de 2 secondes<strong>s<\/strong><br \/>\n<strong>\u00ab\u00a0Busy\u00a0\u00bb<\/strong> : Le programme effectue un (relativement) long calcul<\/p>\n<p style=\"text-align: justify\"><a href=\"https:\/\/bioinfo.iric.ca\/wpbioinfo\/wp-content\/uploads\/2016\/03\/Screen-Shot-2016-03-25-at-22.54.39.png\" rel=\"attachment wp-att-2084\"><br \/>\n<img decoding=\"async\" class=\" wp-image-2084 aligncenter\" src=\"https:\/\/bioinfo.iric.ca\/wpbioinfo\/wp-content\/uploads\/2016\/03\/Screen-Shot-2016-03-25-at-22.54.39-300x232.png\" alt=\"Screen Shot 2016-03-25 at 22.54.39\" width=\"728\" height=\"563\" srcset=\"https:\/\/bioinfo.iric.ca\/wpbioinfo\/wp-content\/uploads\/2016\/03\/Screen-Shot-2016-03-25-at-22.54.39-180x138.png 180w, https:\/\/bioinfo.iric.ca\/wpbioinfo\/wp-content\/uploads\/2016\/03\/Screen-Shot-2016-03-25-at-22.54.39-300x232.png 300w, https:\/\/bioinfo.iric.ca\/wpbioinfo\/wp-content\/uploads\/2016\/03\/Screen-Shot-2016-03-25-at-22.54.39-768x594.png 768w, https:\/\/bioinfo.iric.ca\/wpbioinfo\/wp-content\/uploads\/2016\/03\/Screen-Shot-2016-03-25-at-22.54.39-1024x792.png 1024w, https:\/\/bioinfo.iric.ca\/wpbioinfo\/wp-content\/uploads\/2016\/03\/Screen-Shot-2016-03-25-at-22.54.39.png 1207w\" sizes=\"(max-width: 728px) 100vw, 728px\" \/><br \/>\n<\/a><\/p>\n<p style=\"text-align: justify\"><strong>R\u00e9sultats<\/strong> : Pour la version <strong>\u00ab\u00a0idle\u00a0\u00bb<\/strong>, la vitesse d\u2019execution des 5 threads vs processus est sensiblement la m\u00eame, mis \u00e0 part un l\u00e9ger retard lors du d\u00e9marrage des processus.<\/p>\n<p style=\"text-align: justify\">Par contre, on remarque que lorsqu\u2019il s\u2019agit d\u2019op\u00e9rations co\u00fbteuses en m\u00e9moire, les threads sont bien moins performants que les processus.<\/p>\n<p style=\"text-align: justify\">Pour plus d\u2019informations sur la provenance de ce code et de ces images, consulter le <a href=\"http:\/\/nathangrigg.net\/2015\/04\/python-threading-vs-processes\/\" target=\"_blank\">site<\/a>.<br \/>\nComme nous sommes sympas, nous vous avons concoct\u00e9 un petit tableau r\u00e9capitulatif :<\/p>\n<table border=\"1\">\n<caption>\u00a0<\/caption>\n<tbody>\n<tr>\n<th style=\"border-color: #a1a1a1;text-align: center;vertical-align: middle\" scope=\"row\"><strong>Threads<\/strong><\/th>\n<th style=\"text-align: center\"><strong>Processus<\/strong><\/th>\n<\/tr>\n<tr>\n<td>Cr\u00e9er des threads est rapide<\/td>\n<td>La cr\u00e9ation des processus est plus lente<\/td>\n<\/tr>\n<tr>\n<td>Les threads utilisent une m\u00eame m\u00e9moire:<\/p>\n<p>\u2192 La communication est rapide<\/p>\n<p>\u2192 Moins de m\u00e9moire est utilis\u00e9e<\/td>\n<td>Les processus utilisent des espaces de m\u00e9moire s\u00e9par\u00e9s<\/p>\n<p>\u2192 La communication est lente et difficile<\/p>\n<p>\u2192 Une plus grande portion de la m\u00e9moire est utilis\u00e9e<\/td>\n<\/tr>\n<tr>\n<td>Roule sur un seul processeur<\/td>\n<td>Prend avantage des diff\u00e9rents CPUs et cores de la machine<\/td>\n<\/tr>\n<tr>\n<td>Le Global Interpreter Lock (GIL) emp\u00eache l\u2019ex\u00e9cution simultan\u00e9e des threads<\/td>\n<td>Les multiprocess sont ind\u00e9pendants l\u2019un de l\u2019autre, leur permettant ainsi de contourner le GIL<\/td>\n<\/tr>\n<tr>\n<td>Tr\u00e8s bonne m\u00e9thode de communication! (exemple: un serveur qui demande des inputs \u00e0 un script qui est en train de rouler)<\/td>\n<td>Permet de faire gagner du temps en prenant avantage de toutes les capacit\u00e9s de la machine<\/td>\n<\/tr>\n<tr>\n<td>Le module \u2018threading\u2019 est un outil tr\u00e8s puissant qui contient un grand nombre de fonctionnalit\u00e9s<\/td>\n<td>Le module \u2018multiprocessing\u2019 est con\u00e7u pour \u00eatre aussi proche que possible du module \u2018threading\u2019<\/td>\n<\/tr>\n<tr>\n<td>Si un thread crash, tous les autres threads crasheront en cons\u00e9quence<\/td>\n<td>Un processus qui crash n\u2019affectera pas les autres processus, puisqu\u2019ils sont ind\u00e9pendants les uns des autres<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p style=\"text-align: justify\"><sub>Tableau r\u00e9sumant les diff\u00e9rences majeures entre multiprocess et multithread en Python.<\/sub><\/p>\n<p style=\"text-align: justify\">Tout \u00e7a est bien beau, mais en pratique, il nous faut savoir comment utiliser les diff\u00e9rents modules qui nous permettent de profiter de cette extraordinaire invention qu\u2019est le parall\u00e9lisme!<\/p>\n<p style=\"text-align: justify\">\u00c0 notre connaissance, il existe essentiellement trois modules \u2018pythoniens\u2019 capables d\u2019accomplir cette t\u00e2che :<\/p>\n<ol style=\"text-align: justify\">\n<li><a href=\"https:\/\/docs.python.org\/2\/library\/multiprocessing.html\" target=\"_blank\">Le module multiprocessing<br \/>\n<\/a>Nous vous conseillons d\u2019aller voir un excellent article sur le sujet :<br \/>\n<a href=\"https:\/\/bioinfo.iric.ca\/fr\/faites-travailler-vos-cpus\/\" target=\"_blank\">\u201cFaites travailler vos CPUs !\u201d<br \/>\n<\/a><\/li>\n<li><a href=\"https:\/\/docs.python.org\/2\/library\/threading.html\" target=\"_blank\">Le module threading<\/a><a href=\"https:\/\/bioinfo.iric.ca\/fr\/faites-travailler-vos-cpus\/\" target=\"_blank\"><br \/>\n<\/a>Ce module est un excellent outil pour parall\u00e9liser des threads en Python. Il est fortement inspir\u00e9 de Java, et fourni un r\u00e9el arsenal d\u2019outils pour les programmeurs exp\u00e9riment\u00e9s. Cependant, la richesse de ce module fait en sorte que \u00e7a reste quand m\u00eame une librairie un peu complexe et relativement longue \u00e0 ma\u00eetriser. Pour ceux qui ne souhaitent pas apprendre le module <strong>threading<\/strong>, il existe une sous-librairie, <strong>multiprocessing.dummy<\/strong>, permettant de cr\u00e9er des <strong>threads<\/strong>. Cette derni\u00e8re peut \u00eatre vue comme un clone de la librairie <strong>multiprocessing<\/strong> et permet d\u2019utiliser la fonction <strong>\u00ab\u00a0map\u00a0\u00bb<\/strong> comme le ferait celle-ci (pour des exemples d&rsquo;utilisation de <strong>\u00ab\u00a0map\u00a0\u00bb<\/strong>, se r\u00e9f\u00e9rer \u00e0 l\u2019article cit\u00e9 dans la section pr\u00e9c\u00e9dente).<br \/>\nVoici un exemple d\u2019appel \u00e0 cette fonction :<\/li>\n<\/ol>\n<pre><code class=\"python\"><code class=\"python\">from multiprocessing.dummy import Pool as ThreadPool<\/code><\/code><\/pre>\n<p><em>remarque<\/em> : Nous avons inclu cette librairie <strong>\u00ab\u00a0multiprocessing\u00a0\u00bb<\/strong> dans cette section bien qu&rsquo;elle ne fasse pas partie du module <strong>\u00ab\u00a0threading\u00a0\u00bb<\/strong> mais bien du module <strong>&lsquo;multiprocessing&rsquo;<\/strong>. Si nous avons fait ce choix c&rsquo;est parce que <strong>\u00ab\u00a0multiprocssing.dummy\u00a0\u00bb<\/strong> permet de cr\u00e9er des <strong>threads<\/strong>.<\/p>\n<ol style=\"text-align: justify\">\n<li><a href=\"https:\/\/docs.python.org\/3\/library\/concurrent.futures.html\" target=\"_blank\">Le module concurrent.futures<br \/>\n<\/a>Ce module est relativement r\u00e9cent, il est une simplification des 2 modules pr\u00e9c\u00e9dents. Mais ce n\u2019est pas tout, pour chaque appel d\u2019une fonction, un objet \u00ab\u00a0futur\u00a0\u00bb est cr\u00e9\u00e9, permettant de suivre l\u2019\u00e9volution du processus (ou thread) et offre une plus grande libert\u00e9 d\u2019action. Il va de soi que cette m\u00e9thode est plus lente que les pr\u00e9c\u00e9dentes.<br \/>\nMais si vous devez investir du temps pour apprendre \u00e0 ma\u00eetriser une librairie en Python, ce serait cette derni\u00e8re.<\/li>\n<\/ol>\n<p style=\"text-align: justify\"><a href=\"https:\/\/bioinfo.iric.ca\/fr\/faites-travailler-vos-cpus\/\" target=\"_blank\"><br \/>\n<\/a>Merci et f\u00e9licitations d&rsquo;avoir lu cet article jusqu\u2019ici. N\u2019h\u00e9sitez pas \u00e0 laisser un commentaire d\u2019une quelconque nature: plus on aura de commentaires, plus nous pourrons fournir des articles de qualit\u00e9!<\/p>\n<\/div><div class=\"fusion-clearfix\"><\/div><\/div><\/div><\/div><\/div>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":13,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[32,26],"tags":[52,83],"class_list":["post-2097","post","type-post","status-publish","format-standard","hentry","category-performance-fr-2","category-langage-python","tag-multiprocessing","tag-multithreads-2"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/posts\/2097","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/users\/13"}],"replies":[{"embeddable":true,"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/comments?post=2097"}],"version-history":[{"count":12,"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/posts\/2097\/revisions"}],"predecessor-version":[{"id":2709,"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/posts\/2097\/revisions\/2709"}],"wp:attachment":[{"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/media?parent=2097"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/categories?post=2097"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/tags?post=2097"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}