# Stopwatch 管理器

## 指导 <a href="#guide" id="guide"></a>

当我们在一些简单的项目中使用 Stopwatch 时，通常仅创建一个 Stopwatch 实例。

```python
demo_stopwatch: Stopwatch = Stopwatch()
```

但在一些中、大型项目中，我们可能会需要使用多个 Stopwatch 实例并在项目全局共享。此时，上文中直接创建的 Stopwatch 实例可能不便于在全局范围内共享和维护。而当需要多个 Stopwatch 实例时，对实例对象的管理和维护将变得复杂。

在 0.1.3 或更高版本中，我们可以使用一个或多个 Stopwatch 管理器托管这些 Stopwatch 实例并在全局范围内共享，开发者也无需维护这些实例对象。

在下文中，我们将通过几段连续的 Python 代码向您演示如何使用 Stopwatch 管理器。

### 导入模块 <a href="#import-module" id="import-module"></a>

在使用 Stopwatch 管理器之前，我们应该导入 `StopwatchManager`：

```python
from stopwatch import StopwatchManager
```

如果您不需要多个 Stopwatch 管理器实例，可以直接使用默认的 Stopwatch 管理器并在全局范围内共享。

```python
from stopwatch import default_manager
```

符号 `default_manager` 是一个数据类型为 `StopwatchManager` 的变量，它在包 `stopwatch` 被首次导入时创建。因此，您可以在全局范围内导入此变量，以在全局范围内共享 Stopwatch 默认管理器实例。

### 创建管理器 <a href="#create-manager" id="create-manager"></a>

如果 Stopwatch 默认管理器不足以满足需求，您可以额外创建多个 Stopwatch 管理器实例。

```python
demo_manager: StopwatchManager = StopwatchManager(
    max_stopwatch_count = None
)
```

类 `StopwatchManager` 的构造器方法有一个数据类型为 `int` 的可选参数 `max_stopwatch_count`，该参数指示被创建的 Stopwatch 管理器最多可以同时托管多少个 Stopwatch 实例。如果未提供该参数或值为 `None`，则不限制 Stopwatch 实例个数。

### 添加 Stopwatch <a href="#add-stopwatch" id="add-stopwatch"></a>

我们在本篇指导文章的开头，定义了名为 `demo_stopwatch` 的变量，它是一个 Stopwatch 实例。现在我们尝试将 `demo_stopwatch` 添加到上文创建的 Stopwatch 管理器实例 `demo_manager` 中。

```python
demo_manager.add(
    stopwatch_name = 'guide::demo1', 
    stopwatch_instance = demo_stopwatch
)
```

方法 `add` 有 2 个参数，它们分别是：

| 参数名                 | 类型        | 必选   | 描述                   |
| ------------------- | --------- | ---- | -------------------- |
| stopwatch\_name     | str       | True | Stopwatch 实例唯一名称。    |
| stopwatch\_instance | Stopwatch | True | 被添加的 Stopwatch 实例对象。 |

我们强烈建议您使用 `namespace::name` 的形式命名 Stopwatch 实例唯一名称，这样当多个协作项目在同一全局范围内，不会引发 Stopwatch 实例唯一名称冲突，Namespace 可以是项目名称。

{% hint style="danger" %}
请注意，Stopwatch 实例名称在当前 Stopwatch 管理器范围内必须是唯一的，否则将引发 StopwatchNameError 异常。
{% endhint %}

如果当前 Stopwatch 管理器内已托管的 Stopwatch 实例个数等于或超过 `max_stopwatch_count` 参数的限制，将引发 `MaxLimitError` 异常。

### 创建 Stopwatch <a href="#create-stopwatch" id="create-stopwatch"></a>

除了向 Stopwatch 管理器添加已有 Stopwatch 实例外，我们也可以直接在 Stopwatch 管理器中创建一个具有默认构造器方法参数的新 Stopwatch 实例。

```python
new_stopwatch: Stopwatch = demo_manager.create(
    stopwatch_name = 'guide::demo2'
)
```

方法 `create` 具有 1 个数据类型为 `str` 的参数 `stopwatch_name`，该参数指示新创建并添加的 Stopwatch 实例唯一名称。创建并添加后，该方法返回数据类型为 Stopwatch 的 Stopwatch 实例对象。

我们还可以创建并添加一个 Stopwatch 实例后，使它开始计时。

```python
new_stopwatch: Stopwatch = demo_manager.create_and_start(
    stopwatch_name = 'guide::demo2'
)
```

### 移除 Stopwatch <a href="#remove-stopwatch" id="remove-stopwatch"></a>

当我们需要从 Stopwatch 管理器中移除指定唯一名称的 Stopwatch 实例时，我们可以这样做。

```python
demo_manager.remove(
    stopwatch_name = 'guide::demo2'
)
```

如果需要移除所有 Stopwatch 实例，可以使用 `clear` 方法。

```python
demo_manager.clear()
```

{% hint style="danger" %}
请注意，如果指定 Stopwatch 实例唯一名称不存在，将引发 StopwatchNameError 异常。
{% endhint %}

### 获得 Stopwatch <a href="#get-stopwatch" id="get-stopwatch"></a>

当我们需要在项目全局范围内共享 Stopwatch 实例时，无需维护这些 Stopwatch 实例，而是使用 Stopwatch 实例的唯一名称从 Stopwatch 管理器中获得它。

```python
demo_stopwatch: Stopwatch = demo_manager.get(
    stopwatch_name = 'guide::demo1'
)
```

如果我们需要确定一个 Stopwatch 实例是否存在，可以使用 `has` 方法检查。

```python
if not demo_manager.has(
    stopwatch_name = 'guide::demo2'
):
    print('no such stopwatch')
```

### 管理 Stopwatch <a href="#management-stopwatch" id="management-stopwatch"></a>

#### 获取实例个数 <a href="#get-count" id="get-count"></a>

当我们需要获取指定 Stopwatch 管理器已托管的 Stopwatch 实例个数时，可以使用 `get_count` 方法。

```python
number_of_stopwatchs: int = demo_manager.get_count()
```

方法 `get_count` 具有 `int` 数据类型的返回值，其指示 Stopwatch 实例个数。

#### 使实例开始计时 <a href="#starts" id="starts"></a>

当我们需要使指定一批或全部 Stopwatch 实例开始计时时，可以使用 `starts` 方法。

```python
demo_manager.starts(
    stopwatch_names = [
        'guide::demo1', 
        ...
    ]
)
```

方法 `starts` 有一个数据类型为 `list` 的可选参数 `stopwatch_names`，其指示需要开始的 Stopwatch 实例的唯一名称列表。如果未提供此参数或值为 `None`，则使所有 Stopwatch 实例开始计时。

该方法返回数据类型为 `int` 的返回值，指示实际开始的 Stopwatch 实例个数。

{% hint style="danger" %}
请注意，如果有一个或多个实例已经开始计时，该方法将跳过而非引发 StatusError 异常。
{% endhint %}

#### 使实例停止计时 <a href="#stops" id="stops"></a>

同样的，我们也可以使指定一批或全部 Stopwatch 实例停止计时。

```python
demo_manager.stops(
    stopwatch_names = [
        'guide::demo1', 
        ...
    ]
)
```

该方法返回数据类型为 `int` 的返回值，指示实际停止的 Stopwatch 实例个数。

{% hint style="danger" %}
请注意，如果有一个或多个实例已经停止计时，该方法将跳过而非引发 StatusError 异常。
{% endhint %}

#### 使实例重置 <a href="#resets" id="resets"></a>

除了开始计时、停止计时外，我们也可以使指定一批或全部 Stopwatch 实例重置。

```python
demo_manager.resets(
    stopwatch_names = [
        'guide::demo1', 
        ...
    ]
)
```

#### 获取实例总计时时长 <a href="#get-watchs" id="get-watchs"></a>

当我们需要获取指定一批或全部 Stopwatch 实例的当前总计时时长时，可以使用 `get_watchs` 方法。

```python
total_of_watch: float = demo_manager.get_watchs(
    stopwatch_names = [
        'guide::demo1', 
        ...
    ], 
    watch_precision = 3
)
```

方法 `get_watchs` 相对于上文所提及的其他方法有一个额外数据类型为 `int` 的可选参数 `watch_precision`，其指示获取总计时时长的精度（小数点位数）。如果未提供此参数或值为 `None`，其行为与 Stopwatch 实例的 `get_watch` 方法对参数 `watch_precision` 的行为一致。

## 示例 <a href="#example" id="example"></a>

### 源代码 <a href="#source-code" id="source-code"></a>

{% code title="quickstart.py" %}

```python
# quickstart.py is python-3.7.4 source file

import time

from stopwatch import Stopwatch
from stopwatch import StopwatchManager


# define main function

def main():

    # create a stopwatch manager
    
    demo_manager: StopwatchManager = StopwatchManager(
        max_stopwatch_count = 64
    )
    
    # Start timing after creating and adding a stopwatch instance to the manager
    
    demo_manager.create('guide::demo1').start()
    
    # simulated program time-consuming operation
    
    time.sleep(1)
    
    # get the stopwatch instance from the manager and stop timing.
    
    demo_manager.get('guide::demo1').stop()
    
    # total time duration after getting a stopwatch instance from the manager
    
    print(demo_manager.get('guide::demo1').get_watch())
    
    # remove the stopwatch instance from the manager.
    
    demo_manager.remove('guide::demo1')


# define virtual main function

if __name__ == '__main__':
    main()
```

{% endcode %}

### 运行结果 <a href="#result" id="result"></a>

```
1.0
```
