prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Exception calling application: dictionary changed size during iteration
  The exception occasionally happens when the worker reports gradients to ps.
  ![image](https://user-images.githubusercontent.com/18071380/76288063-d3925380-62e0-11ea-869f-64cccb4e7d37.png)
  
  
  </issue>
  <code>
  [start of elasticdl/python/ps/embedding_table.py]
  1 import numpy as np
  2 import tensorflow as tf
  3 
  4 from elasticdl.proto.elasticdl_pb2 import EmbeddingTableInfo
  5 from elasticdl.python.common.dtypes import dtype_numpy_to_tensor
  6 
  7 
  8 class EmbeddingTable(object):
  9     """
  10     EmbeddingTable is used to store embedding parameters of an embedding
  11     layer. The name of an embedding table is actually the embedding layer
  12     name. It uses a dictionary to store embedding vectors, the key is the
  13     item id, the value is a 1-D numpy.ndarray.
  14 
  15     Embedding vectors are lazily initialized in parameter server.
  16     EmbeddingTable also has dim and initializer fields. Inside the get
  17     interface of EmbeddingTable, if the id is not in the embedding_vectors
  18     dictionary, the corresponding value will be initialized.
  19     """
  20 
  21     def __init__(self, name, dim=None, initializer=None, is_slot=False):
  22         """
  23         Args:
  24             name: The embedding table name.
  25             dim: The dimension of embeddings in this embedding table.
  26             initializer: The initializer to initialize new embeddings. If this
  27                 embedding table is for slots, `initializer` is a float and this
  28                 table will initialize with constant initializer. Otherwise
  29                 `initializer` is the name of Keras initializer.
  30             is_slot: A bool. True for storing slot variable, otherwise false.
  31         """
  32         self.name = name
  33         self.dim = dim
  34         self.initializer_value = initializer
  35         # set dtype to float32
  36         self.dtype = np.dtype("float32")
  37         if is_slot:
  38             self.initializer = tf.keras.initializers.Constant(
  39                 float(self.initializer_value)
  40             )
  41         else:
  42             self.initializer = tf.keras.initializers.get(
  43                 self.initializer_value
  44             )
  45         self.is_slot = is_slot
  46         self.embedding_vectors = {}
  47 
  48     def get(self, indices):
  49         if len(indices) == 0:
  50             return None
  51         values = []
  52         for i in indices:
  53             value = self.embedding_vectors.get(i, None)
  54             if value is None:
  55                 value = self.initializer(shape=(self.dim,)).numpy()
  56                 self.embedding_vectors[i] = value
  57             values.append(value)
  58         return np.stack(values)
  59 
  60     def set(self, indices, values):
  61         # TODO(qijun) need to add a RWLock in Sync-SGD
  62         for index, i in enumerate(indices):
  63             embedding_vector = values[index]
  64             self.embedding_vectors[i] = embedding_vector
  65 
  66     def clear(self):
  67         self.embedding_vectors.clear()
  68 
  69     def to_indexed_slices(self):
  70         indices = []
  71         embedding_vectors = []
  72         for id, embedding_vector in self.embedding_vectors.items():
  73             indices.append(id)
  74             embedding_vectors.append(embedding_vector)
  75         return tf.IndexedSlices(
  76             values=np.array(embedding_vectors), indices=np.array(indices)
  77         )
  78 
  79     def to_embedding_table_info_pb(self):
  80         """Convert the embedding table information to a protobuf"""
  81         embedding_pb = EmbeddingTableInfo()
  82         embedding_pb.name = self.name
  83         embedding_pb.dim = self.dim
  84         embedding_pb.initializer = str(self.initializer_value)
  85         embedding_pb.dtype = dtype_numpy_to_tensor(self.dtype)
  86         return embedding_pb
  87 
  88     def get_table_size(self):
  89         """Get the element count of an embedding table"""
  90         if len(self.embedding_vectors) > 0:
  91             element_size = list(self.embedding_vectors.values())[0].itemsize
  92             size = self.dim * len(self.embedding_vectors) * element_size
  93             return size
  94         return 0
  95 
  96     def debug_info(self):
  97         return (
  98             "Embedding param name: %s\n  shape: [%d, %d]\n  size: %d bytes\n"
  99             % (
  100                 self.name,
  101                 len(self.embedding_vectors),
  102                 self.dim,
  103                 self.get_table_size(),
  104             )
  105         )
  106 
  107 
  108 # TODO(bug): create_embedding_table does not create EmbeddingTable correctly
  109 #     if it is a slot table.
  110 def create_embedding_table(embedding_table_info_pb):
  111     name = embedding_table_info_pb.name
  112     dim = embedding_table_info_pb.dim
  113     initializer = embedding_table_info_pb.initializer
  114     return EmbeddingTable(name, dim, initializer)
  115 
  116 
  117 def get_slot_table_name(embedding_name, slot_name):
  118     return embedding_name + "-" + slot_name
  119
  [end of elasticdl/python/ps/embedding_table.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/elasticdl/python/ps/embedding_table.py b/elasticdl/python/ps/embedding_table.py
  --- a/elasticdl/python/ps/embedding_table.py
  +++ b/elasticdl/python/ps/embedding_table.py
  @@ -1,3 +1,5 @@
  +import threading
  +
   import numpy as np
   import tensorflow as tf
   
  @@ -44,6 +46,7 @@
               )
           self.is_slot = is_slot
           self.embedding_vectors = {}
  +        self._lock = threading.Lock()
   
       def get(self, indices):
           if len(indices) == 0:
  @@ -52,8 +55,9 @@
           for i in indices:
               value = self.embedding_vectors.get(i, None)
               if value is None:
  -                value = self.initializer(shape=(self.dim,)).numpy()
  -                self.embedding_vectors[i] = value
  +                with self._lock:
  +                    value = self.initializer(shape=(self.dim,)).numpy()
  +                    self.embedding_vectors[i] = value
               values.append(value)
           return np.stack(values)
   
  @@ -69,9 +73,10 @@
       def to_indexed_slices(self):
           indices = []
           embedding_vectors = []
  -        for id, embedding_vector in self.embedding_vectors.items():
  -            indices.append(id)
  -            embedding_vectors.append(embedding_vector)
  +        with self._lock:
  +            for id, embedding_vector in self.embedding_vectors.items():
  +                indices.append(id)
  +                embedding_vectors.append(embedding_vector)
           return tf.IndexedSlices(
               values=np.array(embedding_vectors), indices=np.array(indices)
           )
  
verification_info: {"golden_diff": "diff --git a/elasticdl/python/ps/embedding_table.py b/elasticdl/python/ps/embedding_table.py\n--- a/elasticdl/python/ps/embedding_table.py\n+++ b/elasticdl/python/ps/embedding_table.py\n@@ -1,3 +1,5 @@\n+import threading\n+\n import numpy as np\n import tensorflow as tf\n \n@@ -44,6 +46,7 @@\n             )\n         self.is_slot = is_slot\n         self.embedding_vectors = {}\n+        self._lock = threading.Lock()\n \n     def get(self, indices):\n         if len(indices) == 0:\n@@ -52,8 +55,9 @@\n         for i in indices:\n             value = self.embedding_vectors.get(i, None)\n             if value is None:\n-                value = self.initializer(shape=(self.dim,)).numpy()\n-                self.embedding_vectors[i] = value\n+                with self._lock:\n+                    value = self.initializer(shape=(self.dim,)).numpy()\n+                    self.embedding_vectors[i] = value\n             values.append(value)\n         return np.stack(values)\n \n@@ -69,9 +73,10 @@\n     def to_indexed_slices(self):\n         indices = []\n         embedding_vectors = []\n-        for id, embedding_vector in self.embedding_vectors.items():\n-            indices.append(id)\n-            embedding_vectors.append(embedding_vector)\n+        with self._lock:\n+            for id, embedding_vector in self.embedding_vectors.items():\n+                indices.append(id)\n+                embedding_vectors.append(embedding_vector)\n         return tf.IndexedSlices(\n             values=np.array(embedding_vectors), indices=np.array(indices)\n         )\n", "issue": "Exception calling application: dictionary changed size during iteration\nThe exception occasionally happens when the worker reports gradients to ps.\r\n![image](https://user-images.githubusercontent.com/18071380/76288063-d3925380-62e0-11ea-869f-64cccb4e7d37.png)\r\n\n", "before_files": [{"content": "import numpy as np\nimport tensorflow as tf\n\nfrom elasticdl.proto.elasticdl_pb2 import EmbeddingTableInfo\nfrom elasticdl.python.common.dtypes import dtype_numpy_to_tensor\n\n\nclass EmbeddingTable(object):\n    \"\"\"\n    EmbeddingTable is used to store embedding parameters of an embedding\n    layer. The name of an embedding table is actually the embedding layer\n    name. It uses a dictionary to store embedding vectors, the key is the\n    item id, the value is a 1-D numpy.ndarray.\n\n    Embedding vectors are lazily initialized in parameter server.\n    EmbeddingTable also has dim and initializer fields. Inside the get\n    interface of EmbeddingTable, if the id is not in the embedding_vectors\n    dictionary, the corresponding value will be initialized.\n    \"\"\"\n\n    def __init__(self, name, dim=None, initializer=None, is_slot=False):\n        \"\"\"\n        Args:\n            name: The embedding table name.\n            dim: The dimension of embeddings in this embedding table.\n            initializer: The initializer to initialize new embeddings. If this\n                embedding table is for slots, `initializer` is a float and this\n                table will initialize with constant initializer. Otherwise\n                `initializer` is the name of Keras initializer.\n            is_slot: A bool. True for storing slot variable, otherwise false.\n        \"\"\"\n        self.name = name\n        self.dim = dim\n        self.initializer_value = initializer\n        # set dtype to float32\n        self.dtype = np.dtype(\"float32\")\n        if is_slot:\n            self.initializer = tf.keras.initializers.Constant(\n                float(self.initializer_value)\n            )\n        else:\n            self.initializer = tf.keras.initializers.get(\n                self.initializer_value\n            )\n        self.is_slot = is_slot\n        self.embedding_vectors = {}\n\n    def get(self, indices):\n        if len(indices) == 0:\n            return None\n        values = []\n        for i in indices:\n            value = self.embedding_vectors.get(i, None)\n            if value is None:\n                value = self.initializer(shape=(self.dim,)).numpy()\n                self.embedding_vectors[i] = value\n            values.append(value)\n        return np.stack(values)\n\n    def set(self, indices, values):\n        # TODO(qijun) need to add a RWLock in Sync-SGD\n        for index, i in enumerate(indices):\n            embedding_vector = values[index]\n            self.embedding_vectors[i] = embedding_vector\n\n    def clear(self):\n        self.embedding_vectors.clear()\n\n    def to_indexed_slices(self):\n        indices = []\n        embedding_vectors = []\n        for id, embedding_vector in self.embedding_vectors.items():\n            indices.append(id)\n            embedding_vectors.append(embedding_vector)\n        return tf.IndexedSlices(\n            values=np.array(embedding_vectors), indices=np.array(indices)\n        )\n\n    def to_embedding_table_info_pb(self):\n        \"\"\"Convert the embedding table information to a protobuf\"\"\"\n        embedding_pb = EmbeddingTableInfo()\n        embedding_pb.name = self.name\n        embedding_pb.dim = self.dim\n        embedding_pb.initializer = str(self.initializer_value)\n        embedding_pb.dtype = dtype_numpy_to_tensor(self.dtype)\n        return embedding_pb\n\n    def get_table_size(self):\n        \"\"\"Get the element count of an embedding table\"\"\"\n        if len(self.embedding_vectors) > 0:\n            element_size = list(self.embedding_vectors.values())[0].itemsize\n            size = self.dim * len(self.embedding_vectors) * element_size\n            return size\n        return 0\n\n    def debug_info(self):\n        return (\n            \"Embedding param name: %s\\n  shape: [%d, %d]\\n  size: %d bytes\\n\"\n            % (\n                self.name,\n                len(self.embedding_vectors),\n                self.dim,\n                self.get_table_size(),\n            )\n        )\n\n\n# TODO(bug): create_embedding_table does not create EmbeddingTable correctly\n#     if it is a slot table.\ndef create_embedding_table(embedding_table_info_pb):\n    name = embedding_table_info_pb.name\n    dim = embedding_table_info_pb.dim\n    initializer = embedding_table_info_pb.initializer\n    return EmbeddingTable(name, dim, initializer)\n\n\ndef get_slot_table_name(embedding_name, slot_name):\n    return embedding_name + \"-\" + slot_name\n", "path": "elasticdl/python/ps/embedding_table.py"}]}