multiprocessing.shared_memory
— Fornece memória compartilhada para acesso direto entre processos¶
Código-fonte: Lib/multiprocessing/shared_memory.py
Novo na versão 3.8.
Este módulo fornece 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 desempenho 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 é mais necessário para nenhum processo, o métodounlink()
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 aclose()
não implica na destruição do próprio bloco de memória compartilhada.
-
unlink
()¶ Solicita que o bloco de memória compartilhada subjacente seja destruído. Para garantir uma limpeza apropriada dos recursos,
unlink()
deve ser chamado uma vez (e apenas uma vez) em todos os processos que precisam do bloco de memória compartilhada. Após solicitar sua destruição, um bloco de memória compartilhada pode ou não ser imediatamente destruído e este comportamento pode divergir entre plataformas. Tentativas de acessar dados dentro do bloco de memória compartilhada depois da chamada dounlink()
podem resultar em erros de acesso de memória. Nota: o último processo restante em um bloco de memória compartilhada pode chamarunlink()
eclose()
em qualquer ordem.
-
buf
¶ Uma visualização de memória do conteúdo do bloco de memória compartilhada.
-
name
¶ Acesso somente leitura ao nome único do bloco de memória compartilhada.
-
size
¶ Acesso somente leitura ao tamanho em 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 deSharedMemoryManager
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étodoshutdown()
na instância. Isso aciona uma chamada deSharedMemory.unlink()
em todos os objetosSharedMemory
gerenciados por esse processo e então para o processo em si. Ao criar instâncias deSharedMemory
através de umSharedMemoryManager
, 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 lista ou similar (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çoSharedMemoryManager
existente de outros processos.-
SharedMemory
(size)¶ Cria e retorna um novo objeto
SharedMemory
com osize
especificado em bytes
-
ShareableList
(sequence)¶ Cria e retorna um novo objeto
ShareableList
, inicializado pelos valores da entradasequence
.
-
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 lista ou similar, 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) eNone
. Este objeto também se diferencia notavelmente do tipo embutidolist
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 oferece suporte à criação dinâmica de uma instância deShareableList
através do fatiamento do objeto.sequence é usado para preencher um
ShareableList
com valores. Defina comoNone
para anexar a umaShareableList
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 umaShareableList
já existente, deve-se especificar o nome único do bloco de memória compartilhada e definirsequence
comoNone
.-
count
(value)¶ Retorna o número de ocorrências de
value
.
-
index
(value)¶ Retorna a primeira posição do índice de
value
. LevantaValueError
sevalue
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()