class_docstr: azure.storage.blob.BlobServiceClient objects internally cache HTTPS connections.
  In order to reuse HTTPS connections, we need to reuse BlobServiceClient objects.
  
  The effect we are going for is for each process or thread in the executor to
  EACH REUSE ITS OWN long-lived BlobServiceClient object.
docstr: Each spawned process will get its own fresh cache.
  
  With each process's cache, each thread gets its own distinct service object.
  
  The cache key includes all BlobServiceClient creation params PLUS process ID and thread ID.
  
  This means that no more than one thread of control will ever access a cache key. This, and
  the fact that dict() operations are thread-safe means that no additional synchronization
  required here.
docstr_tok: ["Each","spawned","process","will","get","its","own","fresh","cache",".","With","each","process","'s","cache",",","each","thread","gets","its","own","distinct","service","object",".","The","cache","key","includes","all","BlobServiceClient","creation","params","PLUS","process","ID","and","thread","ID",".","This","means","that","no","more","than","one","thread","of","control","will","ever","access","a","cache","key",".","This",",","and","the","fact","that","dict","(",")","operations","are","thread-safe","means","that","no","additional","synchronization","required","here","."]
code: def get(
      blob_service_endpoint,
      credential=None,
      max_single_put_size=None,
      max_single_get_size=None,
      max_chunk_get_size=None,
      connection_data_block_size=None,
  ):
      """
      Each spawned process will get its own fresh cache.
  
      With each process's cache, each thread gets its own distinct service object.
  
      The cache key includes all BlobServiceClient creation params PLUS process ID and thread ID.
  
      This means that no more than one thread of control will ever access a cache key. This, and
      the fact that dict() operations are thread-safe means that no additional synchronization
      required here.
      """
      cache_key = (
          os.getpid(),
          threading.get_ident(),
          credential,
          blob_service_endpoint,
          max_single_put_size,
          max_single_get_size,
          max_chunk_get_size,
          connection_data_block_size,
      )
      service_just_created = None
      if cache_key not in _ClientCache._cache:
          service_just_created = _create_blob_service_client(
              blob_service_endpoint,
              credential=credential,
              max_single_put_size=max_single_put_size,
              max_single_get_size=max_single_get_size,
              max_chunk_get_size=max_chunk_get_size,
              connection_data_block_size=connection_data_block_size,
              # BlobServiceClient accepts many more kwargs. We can add passthroughs as/when needed.
          )
          _ClientCache._cache[cache_key] = service_just_created
      service_to_return = _ClientCache._cache[cache_key]
      if (
          service_just_created is not None
          and service_just_created != service_to_return
      ):
          # This condition may not be fatal, but highly unexpected.
          # Each thread of execution gets its own entry, so there *should* be no concurrent insertions
          # on the same key.
          #
          # The Metaflow team REALLY wants to know if this ever happens, but we stop short of raising a
          # fatal exception to not kill user jobs.
          print(
              "METAFLOW WARNING: Azure _ClientCache had the same cache key updated more than once"
          )
      return service_to_return
  
file_path: metaflow/metaflow/plugins/azure/blob_service_client_factory.py
imports: from metaflow.exception import MetaflowException
  from metaflow.metaflow_config import AZURE_STORAGE_BLOB_SERVICE_ENDPOINT
  from metaflow.plugins.azure.azure_utils import create_cacheable_default_azure_credentials, check_azure_deps
  import os
  import threading
label_desc: Use image node_id 2 for calling the _ClientCache obj's underlying member method code with example usage: obj.get(blob_service_endpoint, credential, max_single_put_size, max_single_get_size, max_chunk_get_size, connection_data_block_size) and returns: service_to_return