Совместно используя память между двумя процессами (C, Windows)

Вы не можете напрямую загрузить файл в Google Cloud Storage с помощью функции python open (которая используется matplotlib.pyplot.savefig за кулисами). Вместо этого вам следует использовать клиентскую библиотеку Cloud Storage для Python . Обратитесь к этой документации для подробностей о том, как эта библиотека используется. Это, среди прочего, позволит вам манипулировать файлами и загружать / скачивать их в GCS.

Вам нужно будет импортировать эту библиотеку, чтобы использовать ее, вы можете установить ее, запустив pip install google-cloud-storage и импортировать ее как from google.cloud import storage.

Кроме того, поскольку plt.figure является объектом, а не фактическим изображением .png, которое вы хотите загрузить, вы также не можете напрямую загрузить его в Google Cloud Storage.

Однако вы можете выполнить одно из следующих действий:

Вариант 1 : сохранить изображение локально, а затем загрузить его в облачное хранилище Google:

[1118 ] Используя ваш код:

from google.cloud import storage

def saving_figure(path_logdir):
    data = np.arange(0, 21, 2)
    fig = plt.figure(figsize=(20, 10))
    plt.plot(data)
    fig.savefig("your_local_path/accuracy_loss_graph.png".format(path_logdir))
    plt.close()


    # init GCS client and upload file
    client = storage.Client()
    bucket = client.get_bucket('skin_cancer_mnist')
    blob = bucket.blob('logs/20190116-195604/accuracy_loss_graph.png')  # This defines the path where the file will be stored in the bucket
    your_file_contents = blob.upload_from_filename(filename="your_local_path/accuracy_loss_graph.png")

Вариант 2 : сохраните результат изображения из рисунка в переменную, затем загрузите его в GCS в виде строки (из байтов):

Я нашел следующий ответ StackOverflow, который, кажется, сохраняет изображение фигуры в байтовую строку .png, однако сам не пробовал.

Опять же, основываясь на вашем коде:

from google.cloud import storage
import io
import urllib, base64

def saving_figure(path_logdir):
    data = np.arange(0, 21, 2)
    fig = plt.figure(figsize=(20, 10))
    plt.plot(data)
    fig_to_upload = plt.gcf()

    # Save figure image to a bytes buffer
    buf = io.BytesIO()
    fig_to_upload.savefig(buf, format='png')
    buf.seek(0)
    image_as_a_string = base64.b64encode(buf.read())

    # init GCS client and upload buffer contents
    client = storage.Client()
    bucket = client.get_bucket('skin_cancer_mnist')
    blob = bucket.blob('logs/20190116-195604/accuracy_loss_graph.png')  # This defines the path where the file will be stored in the bucket
    your_file_contents = blob.upload_from_string(image_as_a_string, content_type='image/png')

Редактировать : Оба варианта предполагают, что среда, из которой вы запускаете скрипт, имеет Cloud SDK установлена ​​и активирована учетная запись с аутентификацией в Google Cloud (если у вас ее нет, вы можете проверить эту документацию , в которой объясняется, как это сделать).

28
задан Community 23 May 2017 в 11:53
поделиться

5 ответов

Вы можете попробовать файл с отображением в память .

Этот дает более подробные пошаговые инструкции.

10
ответ дан 28 November 2019 в 03:33
поделиться

Хотя Windows поддерживает разделяемую память через API-интерфейс отображения файлов , вы не можете легко внедрить отображение общей памяти непосредственно в другой процесс, поскольку MapViewOfFileEx не принимает аргумент процесса.

Однако вы можете ввести некоторые данные, выделив память в другом процессе, используя VirtualAllocEx и WriteProcessMemory . Если вы должны были скопировать в дескриптор, используя DuplicateHandle , а затем внедрить заглушку, которая вызывает MapViewOfFileEx , вы могли бы установить отображение совместно используемой памяти в другом процессе. Поскольку, похоже, вы все равно будете вводить код, это должно сработать для вас.

Подводя итог, вам необходимо:

  • Создать анонимный дескриптор сегмента совместно используемой памяти, вызвав CreateFileMapping с INVALID_HANDLE_VALUE для hFile и NULL для lpName.
  • Скопируйте этот дескриптор в целевой процесс с помощью DuplicateHandle
  • Выделите часть памяти для кода, используя VirtualAllocEx , с flAllocationType = MEM_COMMIT | MEM_RESERVE и flProtect = PAGE_EXECUTE_READWRITE
  • Запишите свой код заглушки в эту память, используя WriteProcessMemory . Эта заглушка, вероятно, должна быть написана на ассемблере. Передайте РУЧКУ от DuplicateHandle, написав ее где-то здесь.
  • Выполните свою заглушку, используя CreateRemoteThread . Затем заглушка должна использовать полученную РУЧКУ для вызова MapViewOfFileEx . Затем процессы будут иметь общий сегмент общей памяти.

Вам может показаться немного проще, если ваша заглушка загружает внешнюю библиотеку, то есть просто вызовите LoadLibrary (поиск адреса LoadLibrary оставлен в качестве упражнения для читателя) и выполните свою работу из точка входа библиотеки dllmain. В этом случае использование именованной совместно используемой памяти, вероятно, будет проще, чем работа с DuplicateHandle. См. Статью MSDN о CreateFileMapping для получения более подробной информации, но, по сути, передайте INVALID_HANDLE_VALUE для hFile и имя для lpName.

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

  1. Использовать разделяемую память переменного размера. Ваша заглушка получает размер и либо имя, либо дескриптор общей памяти. Это уместно, если вам нужно обмениваться данными только один раз. Обратите внимание, что размер сегмента общей памяти не может быть легко изменен после создания.
  2. Используйте именованную трубу . Ваша заглушка получает имя или ручку к трубе. Затем вы можете использовать соответствующий протокол для обмена блоками переменного размера - например, напишите size_t для длины, за которой следует фактическое сообщение. Или используйте PIPE_TYPE_MESSAGE и PIPE_READMODE_MESSAGE и следите за ERROR_MORE_DATA, чтобы определить, где заканчиваются сообщения. Это подходит, если вам нужно обмениваться данными несколько раз.

Редактировать 2 : вот эскиз того, как вы могли бы реализовать хранение дескриптора или указателя для своей заглушки:

.db B8            ;; mov eax, imm32
.dl handle_value  ;; fill this in (located at the start of the image + one byte)
;; handle value is now in eax, do with it as you will
;; more code follows...

Вы также можете просто использовать фиксированное имя, которое вероятно, проще.

25
ответ дан bdonlan 28 November 2019 в 03:33
поделиться

Вы можете попробовать использовать Boost.Interprocess для связи между двумя процессами. Но чтобы внедрить код в ранее существующее, не поддерживаемое программное обеспечение, вам, вероятно, придется использовать способ @ bdonlan, используя WriteProcessMemory .

0
ответ дан Vargas 28 November 2019 в 03:33
поделиться

Вы можете использовать общую память

3
ответ дан 28 November 2019 в 03:33
поделиться

Если вы говорите о Windows, то основным препятствием является то, что каждый процесс находится в своем собственном виртуальном адресном пространстве. К сожалению, вы не можете передавать обычные адреса памяти от процесса к процессу и получать ожидаемые результаты. (С другой стороны, все потоки находятся в одном адресном пространстве, поэтому потоки могут видеть память одинаково.)

Windows, однако, имеет общее пространство памяти, к которому вы должны быть очень осторожны. управлять правильно. Любой процесс, который выделяет пространство в общем пространстве памяти, явно отвечает за освобождение этой памяти. Это контрастирует с локальной памятью, которая более или менее исчезает, когда процесс умирает.

См. этот образец статьи MSDN для некоторых идей о том, как вы можете использовать пространство разделяемой памяти, чтобы захватить мир. Эээ, интерфейс с устаревшим программным обеспечением. Или что угодно :) Удачи в любом деле!

0
ответ дан 28 November 2019 в 03:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: