victory的博客

长安一片月,万户捣衣声

0%

CUDA源程序的结构

采用CUDA并行计算编程模型进行编程一般分为以下几个步骤:

  1. 分配GPU内存(使用cudaMalloc()函数进行分配)。

  2. 从CPU内存中拷贝数据到GPU内存(cudaMemcpy())。

  3. 调用CUDA内核函数来完成程序指定的运算(xxxKernel<<<block, grid>>>())。

    在此过程中注意线程的组织方式,通过设置不同block、grid来进行组织。

  4. 将数据从GPU拷回CPU内存(cudaMemcpy())。

  5. 释放GPU内存空间(cudaFree)。

数据划分形式

块划分和周期划分是数据分配给线程的两种不同策略,它们在一些方面存在差异。以下是具体分析:

  • 块划分:在块划分中,一组连续的数据被分到一个块内每个数据块通常具有相同的大小,并以任意次序被安排给一个线程进行处理。线程在同一时间只处理一个数据块,这种方式简化了同步和调度的问题,因为每个线程独立工作在自己的数据块上。
  • 周期划分:周期划分将更少的数据分到一个块内。在这种策略下,每个线程负责处理多个数据块,且这些数据块之间通常是不连续的。相邻的线程会处理相邻的数据块,当一个线程需要选择一个新的数据块时,它必须跳过与当前线程数一样多的数据块。这种划分方式可以提高缓存的利用率,并可能减少内存访问延迟。

总的来说,块划分适合每个线程处理大块连续数据的任务,而周期划分更适合于需要细粒度并行和数据局部性优化的场景。实际选择哪种划分方式取决于具体的应用场景和目标架构的特点。

以下是块划分和周期划分的代码示例:

块划分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import numpy as np

# 定义数据大小和线程数
data_size = 20
num_threads = 4

# 计算每个线程处理的数据量
chunk_size = data_size // num_threads

# 将数据分成块,并分配给线程
data = np.random.rand(data_size)
chunks = [data[i*chunk_size:(i+1)*chunk_size] for i in range(num_threads)]

# 在每个线程中处理数据块
for chunk in chunks:
# 在这里进行数据处理
print(chunk)

周期划分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import numpy as np

# 定义数据大小和线程数
data_size = 20
num_threads = 4

# 计算每个线程处理的数据量
chunk_size = data_size // num_threads

# 将数据分成块,并分配给线程
data = np.random.rand(data_size)
chunks = [data[i::num_threads] for i in range(num_threads)]

# 在每个线程中处理数据块
for chunk in chunks:
# 在这里进行数据处理
print(chunk)

以上代码示例展示了如何将数据划分为块,并将这些块分配给不同的线程进行处理。在块划分中,每个线程处理一个连续的数据块;而在周期划分中,每个线程处理多个不连续的数据块。

自定义失败断言解释

使用pytest测试代码块(Code Block)或函数(Functions)时,通常使用assert语句对代码块或函数的执行结果与预期结果进行比较,从而判断代码块或函数的正确性。如果在测试过程中某测试用例中的断言失败,即代码块或函数的实际执行结果与预期结果不一致,pytest将会报告错误信息。

阅读全文 »

钩子函数、python中定义钩子函数

钩子函数的概念来源于其工作原理,即在系统或框架的特定阶段“钩住”某一刻以执行自定义代码

钩子函数是一种在特定事件发生时由系统自动调用的自定义函数。这个术语“钩子”(hook)形象地描述了这种机制:它允许开发者“钩住”程序执行过程中的某些点,以便在这些点上插入自己的代码。这些函数通常用于响应系统事件、修改程序行为或执行特定任务。以下是钩子函数由来的几个方面:

  • 系统级钩子函数:在操作系统层面,钩子函数可以监视和处理系统消息,如键盘按键、鼠标动作或窗口消息等。这些函数在消息传递到目标之前截获它们,允许开发者执行自定义操作。
  • 编程框架中的钩子函数:在应用程序框架中,钩子函数用于扩展框架的功能而无需修改框架本身的代码。
  • 函数式编程中的钩子函数:在函数式编程中,钩子函数可以用来实现纯函数,确保函数的输出仅依赖于输入并且不产生副作用。

总的来说,钩子函数提供了一种灵活的方式来处理程序流程中的特定事件,使得开发者能够在不改变原有程序结构的情况下,添加或修改功能。

在Python中,可以使用装饰器来实现钩子函数。以下是一个简单的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def hook_decorator(func):
def wrapper(*args, **kwargs):
print("在函数执行前执行的钩子函数")
result = func(*args, **kwargs)
print("在函数执行后执行的钩子函数")
return result
return wrapper

@hook_decorator
def example_function():
print("这是一个示例函数")

example_function()

"""
输出结果:
在函数执行前执行的钩子函数
这是一个示例函数
在函数执行后执行的钩子函数
"""

纯函数

纯函数(Pure Function)是一种在函数式编程中非常重要的概念,它指的是那些给定相同的输入,总是返回相同输出,并且在执行过程中不会产生副作用的函数

纯函数的核心特征包括:

  • 相同的输入产生相同的输出:这意味着如果两次调用函数时的参数完全相同,那么这两次调用的结果也应该是相同的。
  • 无副作用:纯函数在执行过程中不会改变任何状态,也不会与系统外部有任何可观察的交互,例如修改全局变量、进行I/O操作等。
  • 结果只依赖于输入参数:函数的返回值只能由它的参数决定,不依赖于任何外部状态或额外的输入。

纯函数的优势在于它们具有可预测性,易于测试和重用。由于它们的输出完全由输入决定,因此可以在不产生副作用的情况下自由地替换和使用。

pytest异常断言

异常断言即测试待测代码段是否会抛出特定的异常。异常断言最常用的两种方式如下:

  1. pytest.raises()
1
2
3
4
5
6
7
8
9
10
import pytest


def test_zero_division():
# pytest.raises(ZeroDivisionError)作为一个上下文管理器(context manageer)断言with后的代码块是否会抛出“ZeroDivisionError”除零异常
with pytest.raises(ZeroDivisionError) as excpinfo:
1 / 0

# 异常信息excpinfo中匹配除零异常信息“division by zero”
assert excpinfo.match("division by zero")
  1. @pytest.mark.xfail
1
2
3
4
5
6
7
def f():
raise IndexError()

# @pytest.mark.xfail(raises=IndexError)是一个python装饰器,用于标记(mark)一个测试用例为预期失败,该例子中若f()函数抛出IndexError异常,则标记该测试为预期失败,测试报告(report)中会报告一个1 xfail,若f()函数未抛出IndexError异常,则测试报告中会报告一个1 xpass
@pytest.mark.xfail(raises=IndexError)
def test_f():
f()

注意:

pytest.mark.xfailraises参数一起使用可能更适合于记录未修复的bug,使用pytest.reises()可能更适合于测试自己的代码故意引发的异常的情况。

GPU加速原理

GPU加速的原理是利用多核处理器进行并行运算来实现程序的加速运行**。与CPU不同,GPU拥有数以千计的核心,专门为同时处理多任务而设计,可以高效地处理并行任务。

CPU几倍很强的通用性,可以处理不同类型的数据,同时擅长处理逻辑判断导致的大量分支跳转和中断处理,CPU相当于一个博学多闻的博士在完成一项工作。而GPU处理的数据类型高度统一,且GPU有数以千计的核心,可以并行计算任务,相当于1000个小学生在完成一个任务,呈现“人多力量大”的优势。

实际使用中,GPU需要CPU的配合来完成任务的计算,并行计算部分会运行在GPU上,串行计算部分运行在CPU上,CPU负责总体的程序流程。

参考资料:GPU加速原理,博主写的非常详细!

如何调用pytest

pytest支持命令行参数选择特定的tests去执行,以下是常见的一些选择方法。

1
2
3
4
5
6
7
# run tests in a module
# 运行测试文件中的所有符合pytest测试发现规则的测试用例(测试文件中符合test_*()的函数、TestXxx类中的测试用例)
pytest test_mod.py

# run tests in a directory
# 运行testing目录下的所有文件名符合test_*.py或*_test.py的测试文件中的测试用例
pytest testing/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# run tests by keyword expressions
pytest -k "MyClass and not method"
# 通过关键词表达式指定pytest运行的测试用例,pytest会在testpaths或者当前目录下找到类名为TestMyClass的类中的方法名不带method的方法去执行。如下示例,运行pytest -k "MyClass and not method"会执行test_a方法而不会运行test_method_add()方法

# 编写测试文件test_keyword_exp.py
def add(a, b):
return a + b


class TestMyClass:
def test_a(self):
assert "a" == "a"

def test_method_add(self):
assert add(1, 2) == 3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# run tests by collection arguments

# To run a specific test within a module
# 运行test_mod.py测试文件中的test_func测试用例
pytest tests/test_mod.py::test_func

# To run all tests in a class:
# 运行test_mod.py测试文件中的TestClass类中的测试用例
pytest tests/test_mod.py::TestClass

# Specifying a specific test method:
# 运行test_mod.py测试文件中的TestClass类中的test_method测试用例
pytest tests/test_mod.py::TestClass::test_method

# Specifying a specific parametrization of a test:
# 运行test_mod.py测试文件中的带参数的test_func测试用例
pytest tests/test_mod.py::test_func[x1,y2]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Run tests by marker expressions
# 运行带有@pytest.mark.slow装饰器的测试
pytest -m slow

# 以下示例中,pytest将运行test_a测试用例,而不会运行test_b测试用例
import pytest

class TestMarkDecoration:
@pytest.mark.slow
def test_a(self):
assert 1 == 1

@pytest.mark.quick
def test_b(self):
assert 2 == 2
1
2
3
# run tests from packages
pytest --pyargs pkg.testing
# 这将导入pkg.testing,并使用其文件系统位置从中查找和运行测试