Execute function `fn()` inside the critical section. `fn` should not accept any arguments. To add extra arguments to when calling `fn` in the critical section, create a lambda: ```python critical_section.execute(lambda: fn(*my_args, **my_kwargs)) ``` Args: fn: The f
(self, fn, exclusive_resource_access=True, name=None)
| 187 | return self._handle.op.name |
| 188 | |
| 189 | def execute(self, fn, exclusive_resource_access=True, name=None): |
| 190 | """Execute function `fn()` inside the critical section. |
| 191 | |
| 192 | `fn` should not accept any arguments. To add extra arguments to when |
| 193 | calling `fn` in the critical section, create a lambda: |
| 194 | |
| 195 | ```python |
| 196 | critical_section.execute(lambda: fn(*my_args, **my_kwargs)) |
| 197 | ``` |
| 198 | |
| 199 | Args: |
| 200 | fn: The function to execute. Must return at least one tensor. |
| 201 | exclusive_resource_access: Whether the resources required by |
| 202 | `fn` should be exclusive to this `CriticalSection`. Default: `True`. |
| 203 | You may want to set this to `False` if you will be accessing a |
| 204 | resource in read-only mode in two different CriticalSections. |
| 205 | name: The name to use when creating the execute operation. |
| 206 | |
| 207 | Returns: |
| 208 | The tensors returned from `fn()`. |
| 209 | |
| 210 | Raises: |
| 211 | ValueError: If `fn` attempts to lock this `CriticalSection` in any nested |
| 212 | or lazy way that may cause a deadlock. |
| 213 | ValueError: If `exclusive_resource_access == True` and |
| 214 | another `CriticalSection` has an execution requesting the same |
| 215 | resources as `fn``. Note, even if `exclusive_resource_access` is |
| 216 | `True`, if another execution in another `CriticalSection` was created |
| 217 | without `exclusive_resource_access=True`, a `ValueError` will be raised. |
| 218 | """ |
| 219 | with ops.name_scope(name, "critical_section_execute", []): |
| 220 | |
| 221 | # Ensure that mutex locking only happens *after* all args and |
| 222 | # kwargs have been executed. This avoids certain types of deadlocks. |
| 223 | lock = gen_resource_variable_ops.mutex_lock(self._handle) |
| 224 | |
| 225 | if not context.executing_eagerly(): |
| 226 | # NOTE(ebrevdo): This is to ensure we don't pick up spurious |
| 227 | # Operations created by other threads. |
| 228 | with ops.get_default_graph()._lock: # pylint: disable=protected-access |
| 229 | existing_ops = ops.get_default_graph().get_operations() |
| 230 | with ops.control_dependencies([lock]): |
| 231 | r = fn() |
| 232 | # TODO(ebrevdo): If creating critical sections in a python loop, this |
| 233 | # makes graph creation time quadratic. Revisit if this |
| 234 | # becomes a problem. |
| 235 | created_ops = (set(ops.get_default_graph().get_operations()) |
| 236 | .difference(existing_ops)) |
| 237 | else: |
| 238 | with ops.control_dependencies([lock]): |
| 239 | r = fn() |
| 240 | |
| 241 | if not context.executing_eagerly(): |
| 242 | self._add_control_dependencies_to_lock(created_ops, lock.op) |
| 243 | |
| 244 | # captured_resources is a list of resources that are directly |
| 245 | # accessed only by ops created during fn(), not by any |
| 246 | # ancestors of those ops in the graph. |