Русский
Русский
English
Статистика
Реклама

Pythonnet. Как запустить C код из Python

Введение

На сегодняшний день Python является одним из самых популярных языков программирования, но даже это не помогает ему покрыть все потребности программистов. Самый очевидный минус чистого CPython - это его скорость, поэтому некоторые программисты выбирают для своих задач другие языки программирования, а кто-то просто реализует узкие места на C/C++ и подключает их к Python.

Однако бывают случаи, когда есть некая база кода, написанного на C#, а возможности быстро переписать всё на Python/C/C++ нет. Тогда встает вопрос как подключить C# к Python?. Для этого была разработана библиотека pythonnet. В этой статье разберем: как запустить C# код из Python и что из этого может получиться.

Реализация

Для сравнения скорости выполнения C# и Python я буду ссылаться на одну из прошлых статей.

Библиотека pythonnet работает с .dll файлами, поэтому весь код необходимо будет преобразовывать в динамически подключаемые библиотеки. Чтобы создать .dll файл из C# необходимо установить visual studio и при создании проекта указать, что проект будет создан для библиотеки классов (я дал название проекту: MyTestCS, в будущем dll файл будет носить такое же название как и проект):

В качестве примера будем использовать магазин из прошлой статьи, который оптимизировали силами самого питона и других языков. Создадим структуру для одного товара на C#:

public struct DataGoods    {        public string name;        public int price;        public string unit;        public DataGoods(string name, int price, string unit)        {            this.name = name;            this.price = price;            this.unit = unit;        }    }

Теперь реализуем класс самого магазина. В нем создадим метод для заполнения магазина товарами:

public class ShopClass    {        public string name;        public List<DataGoods> listGoods;        public ShopClass(string name)        {            this.name = name;this.listGoods = new List<DataGoods>();        }        /// <summary>        /// Метод для создания товаров в магазине        /// </summary>        /// <param name="numberGoods"> Количество объектов в магазине </param>        public void createShopClass(int numberGoods) {            List<DataGoods> lGoods = new List<DataGoods>();            for (int i = 0; i < numberGoods; i++) {                lGoods.Add(new DataGoods("телефон", 20000, "RUB"));                lGoods.Add(new DataGoods("телевизор", 45000, "RUB"));                lGoods.Add(new DataGoods("тостер", 2000, "RUB"));            }            this.listGoods = lGoods;        }   }

После того, как класс был создан, приступим к подключению C# кода к Python проекту. Сначала создадим .dll файл из C# проекта (достаточно нажать команду ctrl+shift+B). В папке bin->debug->netstandart2.0 проекта (путь зависит от того, какие конфигурации среды стоят у вас) появится файл с названием проекта и расширением .dll (именно этот файл будет подключаться к программе на Python).

Далее разберемся с проектом на Python. Необходимо установить библиотеку pythonnet, выполнив команду:

pip install pythonnet

В проекте создадим файл main.py, а также поместим библиотеку MyTestCS.dll в папку с проектом:

Теперь можно подключать библиотеку в main.py, для этого сначала импортируем clr (clr позволяет рассматривать пространства имен CLR как пакеты Python):

import clr

Укажем путь до нашего .dll файла:

pathDLL = os.getcwd() + "\\MyTestCS.dll"

Чтобы подгрузить нужную нам библиотеку необходимо прописать следующий код:

clr.AddReference(pathDLL)

После чего можно импортировать модуль и всё, что в нем содержится. Если напрямую сделать импорт MyTestCS:

import MyTestCSprint(MyTestCS)>>> <module 'MyTestCS'>

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

Создадим экземпляр класса ShopClass и DataGoods через Python и обратимся к полям этих классов.

from MyTestCS import ShopClass, DataGoodsshop = ShopClass("Тест магазин")shop.createShopClass(1)goods = DataGoods("чехол для телефона", 500, "RUB")print(shop.name)>>> Тест магазинprint(shop.listGoods)>>> [<MyTestCS.DataGoods object at 0x000001D04C3FE3C8>, <MyTestCS.DataGoods object at 0x000001D04C3FE438>, <MyTestCS.DataGoods object at 0x000001D04C3FE400>]print(shop.listGoods[1].name, shop.listGoods[1].price, shop.listGoods[1].unit)>>> телевизор 45000 RUBprint(goods.name, goods.price, goods.unit)>>> чехол для телефона 500 RUB

Как итог, получилось вызвать код C# из Python и поработать с классами. Теперь протестируем производительность создания 200*100000 товаров через метод createShopClass:

shop = ShopClass("Тест магазин")s = time.time()shop.createShopClass(200 * 100000)print("СОЗДАНИЕ ТОВАРОВ НА C#:", time.time() - s)>>> СОЗДАНИЕ ТОВАРОВ НА C#: 2.9043374061584473

В прошлой статье время создания такого количества товаров заняло примерно 44 секунды. Использование C# вместо Python позволило ускорить этот процесс примерно в 15 раз, что является очень хорошим результатом.

Проблемы

Однако не может же быть всё настолько хорошо, чтобы броситься переписывать куски кода Python на C#. И это так. Попробуем из Python вручную дополнить товарами магазин:

shop = ShopClass("Тест магазин 1")s = time.time()shop.createShopClass(500000)print("СОЗДАЛИ ТОВАР ЧЕРЕЗ C#:", time.time()-s)>>> СОЗДАЛИ ТОВАР ЧЕРЕЗ C#: 0.07325911521911621shop = ShopClass("Тест магазин 2")s = time.time()for _ in range(500000):        goods1 = DataGoods("телефон", 20000, "RUB")        goods2 = DataGoods("телевизор", 45000, "RUB")        goods3 = DataGoods("тостер", 2000, "RUB")        shop.listGoods.extend([goods1, goods2, goods3])print("СОЗДАЛИ ТОВАР ЧЕРЕЗ PYTHON:", time.time()-s)>>> СОЗДАЛИ ТОВАР ЧЕРЕЗ PYTHON: 5.2899720668792725

И проверим аналогичный код, написанный на Python:

istGoods = []class DataGoods2:        def __init__(self, name, price, unit):            self.name = name            self.price = price            self.unit = units = time.time()for _ in range(500000):        goods1 = DataGoods2("телефон", 20000, "RUB")        goods2 = DataGoods2("телевизор", 45000, "RUB")        goods3 = DataGoods2("тостер", 2000, "RUB")        listGoods.extend([goods1, goods2, goods3])print("СОЗДАЛИ PYTHON ОБЪЕКТ:", time.time()-s)>>> СОЗДАЛИ PYTHON ОБЪЕКТ: 1.2972710132598877

Код чистого питона работает быстрее, чем дополнение объекта, созданного из модуля C#. Это связано с тем, что доступ к объектам, написанным на C#, занимает довольно много времени. Чтобы избежать таких проблем, необходимо писать всю логику работы с классом внутри C# кода, и не выносить эту логику в Python. Изменение скорости выполнения кода будет заметно при подсчете суммы всех товаров. Реализуем функцию подсчета суммы товаров на C# (внутри класса ShopClass):

public long getSumGoods() {    long sumGoods = 0;    foreach (DataGoods goods in this.listGoods) {      sumGoods += goods.price;    }    return sumGoods;}

А также на Python:

shop = ShopClass("Магазин 3")shop.createShopClass(1000000)s = time.time()shop.getSumGoods()print("ВРЕМЯ НА СУММУ ТОВАРОВ C#:", time.time()-s)>>> ВРЕМЯ НА СУММУ ТОВАРОВ C#: 0.0419771671295166sumGoods = 0for goods in shop.listGoods:     sumGoods += goods.priceprint("ВРЕМЯ НА СУММУ ТОВАРОВ PYTHON:", time.time()-s)>>> ВРЕМЯ НА СУММУ ТОВАРОВ PYTHON: 6.205681085586548

Python код выполняется гораздо медленнее, чем внутренние методы C#.

Многопоточность

Так как в C# отсутствует GIL, то мне стало интересно протестировать работу многопоточности в C# и попробовать запустить потоки в C# через Python. Для начала протестируем протестируем создание 3х классов ShopClass последовательно и заполним их 3.000.000 товаров:

public class testShop    {        public void testSpeedNoThread(int count)        {            testShopClass(count);            testShopClass(count);            testShopClass(count);        }        public static void testShopClass(int count)        {            ShopClass shop = new ShopClass("Магазин");            shop.createShopClass(count);        }}

Python код для запуска:

tshop = testShop()s = time.time()tshop.testSpeedNoThread(3000000)print("СОЗДАЕМ ПОСЛЕДОВАТЕЛЬНО 3 МАГАЗИНА:", time.time()-s)>>> СОЗДАЕМ ПОСЛЕДОВАТЕЛЬНО 3 МАГАЗИНА: 2.1849117279052734

Дополним класс testShop для работы с потоками новым методом:

public static void testThread(){    ExThread obj = new ExThread();    Thread thr = new Thread(new ThreadStart(obj.mythread1));    Thread thr2 = new Thread(new ThreadStart(obj.mythread1));    Thread thr3 = new Thread(new ThreadStart(obj.mythread1));    thr.Start();    thr2.Start();    thr3.Start();    thr.Join();    thr2.Join();    thr3.Join();}

И создадим новый вспомогательный класс:

public class ExThread{   public void mythread1()     {         ShopClass shop = new ShopClass("Магазин");         shop.createShopClass(3000000);     }}

Запустим Python код для проверки работы потоков:

s = time.time()tshopThread = testShop()tshopThread.testThread()print("СОЗДАЕМ 3 ПОТОКА C# ДЛЯ 3х МАГАЗИНОВ:", time.time()-s)>>> СОЗДАЕМ 3 ПОТОКА C# ДЛЯ 3х МАГАЗИНОВ: 0.6765928268432617

Вывод

Использование частей кода, написанных на C# в Python возможно, но при таком подходе есть и свои минусы, например, скорость доступа к объектам. Использование pythonnet целесообразно, если имеются какие-то части кода, которые нет возможности переписать на Python, но они требуют подключения к основному проекту на Python.

P.S. есть и другие способы ускорить python, например, написать библиотеку на C/C++ или переписать часть кода на Cython с меньшими проблемами. В данной статье лишь представлена возможность использования C# и Python вместе. Также существует реализация Python для платформы Microsoft.NET под названием IronPython.

Источник: habr.com
К списку статей
Опубликовано: 10.05.2021 10:05:19
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Python

Программирование

Клиентская оптимизация

Net

C

Csharp

Оптимизация

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru