"multiprocessing.shared_memory" --- Fornece memória compartilhada para acesso direto entre processos
****************************************************************************************************

**Código fonte:** >>:origem:`Lib/multiprocessing/shared_memory.py`<<

Novo na versão 3.8.

======================================================================

Este módulo provê uma classe, "SharedMemory", para a alocação e
gerenciamento da memória compartilhada a ser acessada por um ou mais
processos em uma máquina multicore ou de multiprocessamento  simétrico
(SMP). Para ajudar com o gerenciamento do ciclo de vida da memória
compartilhada especialmente entre processos distintos, uma subclasse
de "BaseManager", "SharedMemoryManager", também é fornecida no módulo
"multiprocessing.managers"

Neste módulo, memória compartilhada refere-se a blocos de memória
compartilhada no "estilo UNIX SystemV" (embora não seja
necessariamente implementado explicitamente como tal) e não se refere
a "memória compartilhada distribuída". Este estilo de memória
compartilhada permite que processos distintos potencialmente leiam e
escrevam em uma região comum(ou compartilhada) de memória volátil. Os
processos são convencionalmente limitados a ter acesso somente ao
próprio espaço de memória de processo mas a memória compartilhada
permite o compartilhamento de dados entre processos, evitando a
necessidade de enviar mensagens entre processos contendo estes dados.
Compartilhar dados diretamente via memória pode fornecer ganhos de
performance significativos comparado ao compartilhamento de dados via
disco ou soquete ou outras comunicações que requerem a
serialização/desserialização e cópia dos dados.

class multiprocessing.shared_memory.SharedMemory(name=None, create=False, size=0)

   Cria um novo bloco de memória compartilhado ou anexa a um bloco de
   memória compartilhado existente. A cada bloco de memória
   compartilhado é atribuído um nome único. Desta forma, um processo
   pode criar um bloco de memória compartilhada com um nome particular
   e um processo diferente pode ser anexado a esse mesmo bloco de
   memória compartilhada usando este mesmo nome.

   Como um recurso para compartilhar dados entre processos, os blocos
   de memória compartilhada podem sobreviver ao processo original que
   os criou. Quando um processo não precisa mais acessar um bloco de
   memória compartilhada que ainda pode ser necessário para outros
   processos, o método "close()" deve ser chamado. Quando um bloco de
   memória compartilhada não é mãos necessário para nenhum processo, o
   método "unlink()" deve ser chamado para garantir a limpeza
   apropriada.

   *name* é o nome único para a memória compartilhada requisitada,
   especificado como uma string. Ao criar um novo bloco de memória
   compartilhada, se  "None" (o padrão) é fornecido para o nome, um
   novo nome será gerado.

   *create* controla quando um novo bloco de memória compartilhada é
   criado ("True") ou um bloco de memória compartilhada existente é
   anexado  ("False").

   *size* especifica o número de bytes requeridos ao criar um novo
   bloco de memória compartilhada. Como algumas plataformas optam por
   alocar pedaços de memória com base no tamanho da página de memória
   da própria plataforma, o tamanho exato do bloco de memória
   compartilhada pode ser maior ou igual ao tamanho requerido. Ao
   anexar a um bloco de memória compartilhada existente, o parâmetro
   "size" é ignorado.

   close()

      Encerra o acesso à memória compartilhada desta instância. Para
      garantir a limpeza apropriada dos recursos, todas as instâncias
      devem chamar  "close()" uma vez que a instância não for mais
      necessária. Observe que a chamada "close()" não implica na
      destruição do próprio bloco de memória compartilhada.

   unlink()

      Requests that the underlying shared memory block be destroyed.
      In order to ensure proper cleanup of resources, "unlink()"
      should be called once (and only once) across all processes which
      have need for the shared memory block.  After requesting its
      destruction, a shared memory block may or may not be immediately
      destroyed and this behavior may differ across platforms.
      Attempts to access data inside the shared memory block after
      "unlink()" has been called may result in memory access errors.
      Note: the last process relinquishing its hold on a shared memory
      block may call "unlink()" and "close()" in either order.

   buf

      Uma visualização de memória do conteúdo dos blocos de memória
      compartilhada.

   name

      Acesso somente-leitura ao nome único do bloco de memória
      compartilhada.

   size

      Acesso somente leitura ao tamanho de bytes do bloco de memória
      compartilhada.

O exemplo a seguir demonstra um uso baixo nível de instâncias de
"SharedMemory" :

   >>> from multiprocessing import shared_memory
   >>> shm_a = shared_memory.SharedMemory(create=True, size=10)
   >>> type(shm_a.buf)
   <class 'memoryview'>
   >>> buffer = shm_a.buf
   >>> len(buffer)
   10
   >>> buffer[:4] = bytearray([22, 33, 44, 55])  # Modify multiple at once
   >>> buffer[4] = 100                           # Modify single byte at a time
   >>> # Attach to an existing shared memory block
   >>> shm_b = shared_memory.SharedMemory(shm_a.name)
   >>> import array
   >>> array.array('b', shm_b.buf[:5])  # Copy the data into a new array.array
   array('b', [22, 33, 44, 55, 100])
   >>> shm_b.buf[:5] = b'howdy'  # Modify via shm_b using bytes
   >>> bytes(shm_a.buf[:5])      # Access via shm_a
   b'howdy'
   >>> shm_b.close()   # Close each SharedMemory instance
   >>> shm_a.close()
   >>> shm_a.unlink()  # Call unlink only once to release the shared memory

O exemplo a seguir demonstra um uso prático da classe "SharedMemory"
com NumPy arrays, acessando o mesmo "numpy.ndarray" de dois shells
Python distintos.

   >>> # In the first Python interactive shell
   >>> import numpy as np
   >>> a = np.array([1, 1, 2, 3, 5, 8])  # Start with an existing NumPy array
   >>> from multiprocessing import shared_memory
   >>> shm = shared_memory.SharedMemory(create=True, size=a.nbytes)
   >>> # Now create a NumPy array backed by shared memory
   >>> b = np.ndarray(a.shape, dtype=a.dtype, buffer=shm.buf)
   >>> b[:] = a[:]  # Copy the original data into shared memory
   >>> b
   array([1, 1, 2, 3, 5, 8])
   >>> type(b)
   <class 'numpy.ndarray'>
   >>> type(a)
   <class 'numpy.ndarray'>
   >>> shm.name  # We did not specify a name so one was chosen for us
   'psm_21467_46075'

   >>> # In either the same shell or a new Python shell on the same machine
   >>> import numpy as np
   >>> from multiprocessing import shared_memory
   >>> # Attach to the existing shared memory block
   >>> existing_shm = shared_memory.SharedMemory(name='psm_21467_46075')
   >>> # Note that a.shape is (6,) and a.dtype is np.int64 in this example
   >>> c = np.ndarray((6,), dtype=np.int64, buffer=existing_shm.buf)
   >>> c
   array([1, 1, 2, 3, 5, 8])
   >>> c[-1] = 888
   >>> c
   array([  1,   1,   2,   3,   5, 888])

   >>> # Back in the first Python interactive shell, b reflects this change
   >>> b
   array([  1,   1,   2,   3,   5, 888])

   >>> # Clean up from within the second Python shell
   >>> del c  # Unnecessary; merely emphasizing the array is no longer used
   >>> existing_shm.close()

   >>> # Clean up from within the first Python shell
   >>> del b  # Unnecessary; merely emphasizing the array is no longer used
   >>> shm.close()
   >>> shm.unlink()  # Free and release the shared memory block at the very end

class multiprocessing.managers.SharedMemoryManager([address[, authkey]])

   Uma subclasse de "BaseManager" que pode ser usada para o
   gerenciamento dos blocos de memória compartilhada entre processos.

   Uma chamada ao método "start()" em uma instância de
   "SharedMemoryManager" faz com que um novo processo seja iniciado. A
   única finalidade desse novo processo é gerenciar o ciclo de vida de
   todos os blocos de memória criados através dele. Para acionar a
   liberação de todos os blocos de memória gerenciados por este
   processo, invoque o método "shutdown()" na instância. Isso aciona
   uma chamada de "SharedMemory.unlink()" em todos os objetos
   "SharedMemory" gerenciados por esse processo e então para o
   processo por si só. Ao criar instâncias de "SharedMemory" através
   de um "SharedMemoryManager", evitamos a necessidade de rastrear e
   acionar manualmente a liberação dos recursos de memória
   compartilhada.

   Esta classe fornece métodos para criar e retornar instâncias de
   "SharedMemory" e para criar um objeto tipo lista ("ShareableList")
   apoiado por memória compartilhada.

   Consulte "multiprocessing.managers.BaseManager" para obter uma
   descrição dos argumentos de entrada opcionais herdados *address* e
   *authkey* e como eles podem ser usados para conectar-se a um
   serviço "SharedMemoryManager" existente de outros processos.

   SharedMemory(size)

      Cria e retorna um novo objeto "SharedMemory" com o  "size"
      especificado em bytes

   ShareableList(sequence)

      Cria e retorna um novo objeto "ShareableList" , inicializado
      pelos valores da "sequence" de entrada.

O exemplo a seguir demonstra os mecanismos básicos de um
"SharedMemoryManager":

   >>> from multiprocessing.managers import SharedMemoryManager
   >>> smm = SharedMemoryManager()
   >>> smm.start()  # Start the process that manages the shared memory blocks
   >>> sl = smm.ShareableList(range(4))
   >>> sl
   ShareableList([0, 1, 2, 3], name='psm_6572_7512')
   >>> raw_shm = smm.SharedMemory(size=128)
   >>> another_sl = smm.ShareableList('alpha')
   >>> another_sl
   ShareableList(['a', 'l', 'p', 'h', 'a'], name='psm_6572_12221')
   >>> smm.shutdown()  # Calls unlink() on sl, raw_shm, and another_sl

O exemplo a seguir retrata um padrão potencialmente mais conveniente
para usar objetos "SharedMemoryManager" através da instrução "with"
para garantir que todos os blocos de memória compartilhada  são
liberados depois que não são mais necessários.

   >>> with SharedMemoryManager() as smm:
   ...     sl = smm.ShareableList(range(2000))
   ...     # Divide the work among two processes, storing partial results in sl
   ...     p1 = Process(target=do_work, args=(sl, 0, 1000))
   ...     p2 = Process(target=do_work, args=(sl, 1000, 2000))
   ...     p1.start()
   ...     p2.start()  # A multiprocessing.Pool might be more efficient
   ...     p1.join()
   ...     p2.join()   # Wait for all work to complete in both processes
   ...     total_result = sum(sl)  # Consolidate the partial results now in sl

Ao usar um "SharedMemoryManager" em uma instrução "with", os blocos de
memória compartilhada criados utilizando este gerenciador são todos
liberados quando o bloco de código com a instrução "with" termina sua
execução.

class multiprocessing.shared_memory.ShareableList(sequence=None, *, name=None)

   Fornece um objeto semelhante a uma lista mutável onde todos os
   valores armazenados são armazenados em um bloco de memória
   compartilhada. Isto restringe os valores armazenáveis apenas aos
   tipos de dados embutidos  "int", "float", "bool", "str" (com menos
   de 10M bytes cada), "bytes" (menos de 10M bytes cada), e "None" .
   Este objeto também se diferencia notávelmente do tipo embutido
   "list" uma vez que este não pode ter seu comprimento total
   modificado (ex.: não pode usar append, insert, etc.) e também não
   suporta a criação dinâmica de uma instância de "ShareableList"
   através do fatiamento do objeto.

   *sequence* é usado para preencher um "ShareableList" com valores.
   Defina como "None" para anexar a uma "ShareableList" já existente
   pelo seu nome único de memória compartilhada.

   *name* é um nome único para a memória compartilhada requerida, como
   descrito na definição de "SharedMemory".  Ao anexar a uma
   "ShareableList" já existente, deve-se especificar o nome único do
   bloco de memória compartilhada e definir "sequence" como  "None".

   count(value)

      Retorna o número de ocorrências de "value".

   index(value)

      Retorna a primeira posição do índice de "value". Gera
      "ValueError" se "value" não estiver presente.

   format

      Atributo somente leitura contendo o formato de empacotamento
      "struct" usado por todos os valores armazenados atualmente.

   shm

      A instância de "SharedMemory" onde os valores são armazenados.

O exemplo a seguir demonstra o uso básico de uma instância de
"ShareableList":

>>> from multiprocessing import shared_memory
>>> a = shared_memory.ShareableList(['howdy', b'HoWdY', -273.154, 100, None, True, 42])
>>> [ type(entry) for entry in a ]
[<class 'str'>, <class 'bytes'>, <class 'float'>, <class 'int'>, <class 'NoneType'>, <class 'bool'>, <class 'int'>]
>>> a[2]
-273.154
>>> a[2] = -78.5
>>> a[2]
-78.5
>>> a[2] = 'dry ice'  # Changing data types is supported as well
>>> a[2]
'dry ice'
>>> a[2] = 'larger than previously allocated storage space'
Traceback (most recent call last):
  ...
ValueError: exceeds available storage for existing str
>>> a[2]
'dry ice'
>>> len(a)
7
>>> a.index(42)
6
>>> a.count(b'howdy')
0
>>> a.count(b'HoWdY')
1
>>> a.shm.close()
>>> a.shm.unlink()
>>> del a  # Use of a ShareableList after call to unlink() is unsupported

O exemplo a seguir retrata como um, dois ou mais processos podem
acessar a mesma "ShareableList" fornecendo o nome do bloco de memória
compartilhada por trás dela:

>>> b = shared_memory.ShareableList(range(5))         # In a first process
>>> c = shared_memory.ShareableList(name=b.shm.name)  # In a second process
>>> c
ShareableList([0, 1, 2, 3, 4], name='...')
>>> c[-1] = -999
>>> b[-1]
-999
>>> b.shm.close()
>>> c.shm.close()
>>> c.shm.unlink()
