目录
如果你需要利用多核处理器进行真正的并行计算,你应该考虑使用多进程而不是多线程。Python的multiprocessing模块提供了进行真正并行计算的工具。
函数定义,判断字符串是否包含子字符串:
def contains_substring(a, b):
return b in a
# 使用示例
result = contains_substring("welcome to my world", "world")
print(result) # 输出: True 或 False 根据实际情况
使用Django ORM过滤出特定name的语句:
from django.db import models
# 假设 DiagramNode 模型已经定义好,并且已经迁移到数据库
# 过滤出 name="test_name" 的所有对象列表
objects_list = DiagramNode.objects.filter(name="test_name")
关于Django的事务:
transaction.atomic
是Django的一个上下文管理器,用于确保数据库操作在一个事务块中执行。如果块中的操作发生异常,事务将回滚到开始状态,保证数据的一致性。from_account.balance -= amount
和to_account.balance += amount
是账户资金的转移操作。from_account.save()
和to_account.save()
将更改保存到数据库。try...except...else
结构用于捕获并处理可能发生的异常。如果事务块中的操作成功完成,将执行else
块中的代码,打印"successfully"。
transaction.atomic
的作用是确保在transfer_funds
函数中执行的数据库操作要么全部成功,要么在出现错误时全部撤销,这样可以防止数据库状态的不一致。
使用with
语句写文件操作,并说明with
方法的优点:
with open('./test.txt', 'wb') as f:
try:
f.write("hello world")
except:
pass
# with方法的优点:
# - 确保文件在使用后正确关闭,即使发生异常也会执行finally块中的代码。
# - 代码更加简洁,减少了冗余的try...finally结构。
# - 提供了一种更好的资源管理方式,使得文件操作更加安全。
使用map()
函数和列表推导式处理列表:
# 原始列表
original_list = [1, 2, 3, 4, 5]
# 使用map()函数将列表中的每个元素平方
squared_list = map(lambda x: x**2, original_list)
# 使用列表推导式提取出大于10的数
filtered_list = [x for x in squared_list if x > 10]
print(list(filtered_list)) # 输出: [16, 25]
注意:map()函数返回的是一个map对象,如果你需要打印或者转换为列表,需要使用list()函数进行转换。在上述代码中,我直接将map对象转换为了列表并打印出来。
在这个例子中,lambda x: x**2
是一个匿名函数,它接受一个参数 x
并返回 x
的平方。map()
函数将这个函数应用到 original_list
列表中的每个元素上,生成一个新的迭代器 squared_list
,其中包含了原始列表每个元素的平方值。
最后,我们使用 list()
函数将 squared_list
转换为列表,这样就可以打印出结果了。注意,map()
函数本身并不会修改原始列表,它只是生成了一个新的迭代器。
map()
函数是 Python 中的一个内置函数,它接受一个函数和一个可迭代对象作为参数,然后返回一个 map 对象。map()
函数会对可迭代对象中的每个元素应用传入的函数,并返回一个新的迭代器。
这里是 map()
函数的一些关键点:
-
参数:
- 第一个参数是一个函数,这个函数将被应用到可迭代对象的每个元素上。
- 第二个参数是一个可迭代对象,比如列表、元组等。
-
返回值:
map()
返回的是一个 map 对象,这是一个迭代器,可以被用来迭代处理过后的元素。
-
使用 lambda 函数:
lambda
是 Python 中的匿名函数,它允许你定义一个简短的函数。在map()
函数中使用lambda
可以避免定义一个完整的函数。
-
转换为列表:
- 由于
map()
返回的是一个迭代器,如果你想要得到一个列表,可以使用list()
函数将迭代器转换为列表。
- 由于
-
使用场景:
- 当你想要对一个序列的所有元素执行同一个操作时,使用
map()
是非常方便的。
- 当你想要对一个序列的所有元素执行同一个操作时,使用
单例模式
class Singleton:
__instance = None
def __new__(cls, age, name):
if cls.__instance is None:
cls.__instance = object.__new__(cls)
cls.__instance.age = age
cls.__instance.name = name
return cls.__instance
# 创建实例
a = Singleton(19, "test")
b = Singleton(20, "test2")
# 打印属性
print(b.age) # 打印的是什么值? 19
print(b.name) # test
当 Singleton
类的实例第一次被创建时,__instance
被初始化。当再次尝试创建第二个实例(通过 b = Singleton(20, "test2")
),__new__
方法检查 __instance
是否已经存在;如果存在,它不会创建新的实例,而是返回已经存在的 __instance
。
因此,尽管在创建 b
时传入了 age
为 20
,但是 b
实际上引用的是与 a
相同的实例
Python多线程和多进程:
- 多线程:Python中由于全局解释器锁(GIL)的存在,多线程在执行CPU密集型任务时可能不会带来性能上的提升,因为GIL限制了同一时刻只有一个线程可以执行Python字节码。但在I/O密集型任务中,多线程可以提高性能,因为线程可以在等待I/O操作时让其他线程运行。
- 多进程:Python的多进程可以绕过GIL的限制,因为每个进程有自己的Python解释器和内存空间,因此可以利用多核CPU的优势并行执行。多进程适用于CPU密集型任务。
全局解释器锁(GIL)
全局解释器锁(Global Interpreter Lock,简称GIL) 是 Python 解释器在执行时使用的一种机制,用来同步线程的执行,以避免多线程在执行 Python 字节码时发生冲突。GIL 确保在任何时刻,只有一个线程在执行 Python 字节码。
为什么需要 GIL?
- 内存管理:Python 使用引用计数机制来管理内存,当一个对象的引用计数降到0时,会被垃圾回收。如果没有 GIL,多个线程同时修改对象的引用计数可能会导致内存泄漏或不一致。
- 简化实现:GIL 简化了 CPython(Python 的官方实现)的内存管理和垃圾回收机制,避免了复杂的并发控制。
- 兼容性:许多 Python 扩展模块(如 NumPy)在设计时考虑了 GIL 的存在,它们在执行时需要 GIL 来保证线程安全。
GIL 的限制
- 单线程执行:尽管 GIL 允许多线程存在,但在任何时刻只有一个线程可以执行 Python 字节码。这意味着在 CPU 密集型任务中,多线程并不能带来性能提升,反而因为线程切换和锁的开销导致性能下降。
- 阻塞 I/O:在执行 I/O 操作(如文件读写、网络通信)时,GIL 会被释放,允许其他线程运行。但如果 I/O 操作是阻塞的,GIL 仍然会被持有,