Compare commits

..

17 Commits

Author SHA1 Message Date
bcfc9e15b5 09-24-周三_09-35-36 2025-09-24 09:35:36 +08:00
4f9f49a2e0 09-20-周六_15-53-13 2025-09-20 15:53:13 +08:00
7b53b37b3b 09-20-周六_14-54-32 2025-09-20 14:54:32 +08:00
836df0d56c 09-20-周六_13-44-21 2025-09-20 13:44:21 +08:00
df099c7f1a 09-20-周六_13-43-26 2025-09-20 13:43:27 +08:00
ef0ed27b9e 09-19-周五_14-48-32 2025-09-19 14:48:32 +08:00
66148187d0 09-18-周四_15-54-29 2025-09-18 15:54:29 +08:00
244627cf69 09-18-周四_14-43-27 2025-09-18 14:43:27 +08:00
3ed89009e5 09-18-周四_10-40-47 2025-09-18 10:40:47 +08:00
4222354358 09-16-周二_14-59-42 2025-09-16 14:59:42 +08:00
ed1ace678b 09-16-周二_11-03-29 2025-09-16 11:03:29 +08:00
d5f0bd6570 09-16-周二_10-32-59 2025-09-16 10:32:59 +08:00
47e3b9a068 09-16-周二_10-14-02 2025-09-16 10:14:02 +08:00
355a5a52f3 09-16-周二_10-03-01 2025-09-16 10:03:01 +08:00
36ca88991e 09-16-周二_09-47-26 2025-09-16 09:47:26 +08:00
4d74d5ea44 09-15-周一_16-08-20 2025-09-15 16:08:20 +08:00
44510de885 09-15-周一_16-05-58 2025-09-15 16:05:59 +08:00
13 changed files with 271 additions and 141 deletions

View File

@@ -65,12 +65,12 @@ import time
def timer(func):
def inner(*args,**kwargs):
start = time.time()
func(args,kwargs)
func(*args,**kwargs)
print(time.time() - start)
return inner
@timer
def func1(*args,**kwargs):
print(args,kwargs)
print(*args,**kwargs)
func1('hello world','abc',123,432)
```

View File

@@ -14,7 +14,7 @@ variable = [out_exp_res for out_exp in input_list if out_exp == 2]
30以内所有能被3整除的数
```python
multiples = [i for i in range(30) if i % 3 is 0]
multiples = [i for i in range(30) if i % 3 == 0]
print(multiples)
```
@@ -23,7 +23,7 @@ print(multiples)
```python
def squared(x):
return x*x
multiples = [squared(i) for i in range(30) if i % 3 is 0]
multiples = [squared(i) for i in range(30) if i % 3 == 0]
print(multiples)
```

View File

@@ -79,7 +79,7 @@ for i in range(n):
说明:这段代码for循环 里面的代码会执行n遍因此它消耗的时间是随着n的变化而变
化的因此这类代码都可以用O(n)来表示它的时间复杂度
## 线性对数阶 O(nlogN)
## 线性对数阶 O($$nlogN$$)
```python
n = 100
@@ -102,7 +102,7 @@ for i in range(n):
        j += i
```
说明:平方阶$$O(n2)$$就更容易理解了,如果把$$O(n)$$的代码再嵌套循环一遍,它的时间复杂度就是$$O(n^2)$$这段代码其实就是嵌套了2层n循环它的时间复杂度就是$$O(n*n)$$,即$$O(n^2)$$ 如果将其中一层循环的n改成m那它的时间复杂度就变成了$$O(m*n)$$ 
## 立方阶 O(n³)、K 次方阶 O(n^k)
## 立方阶 O(n³)、K 次方阶 O($$n^k$$)
说明:参考上面的 O(n²) 去理解就好了O(n³)相当于三层 n 循环,其它的类似

View File

@@ -71,12 +71,12 @@ class C:
name = "公有静态字段"
def func(self):
print (C.name)
print(C.name)
class D(C):
def show(self):
print (C.name)
print(C.name)
print(C.name) # 类访问
@@ -94,12 +94,12 @@ class C:
__name = "私有静态字段"
def func(self):
print (C.__name)
print(C.__name)
class D(C):
def show(self):
print (C.__name)
print(C.__name)
print(C.__name) # 不可在外部访问
@@ -140,29 +140,6 @@ obj_son = D();
obj_son.show() # 派生类中访问
```
```python
class C:
def __init__(self):
self.__foo = "私有字段"
def func(self):
print self.foo  # 类内部访问
class D(C):
def show(self):
print self.foo  派生类中访问
obj = C()
obj.__foo # 通过对象访问 ==> 错误
obj.func() # 类内部访问 ==> 正确
obj_son = D();
obj_son.show() # 派生类中访问 ==> 错误
```
```python
class C:
@@ -172,14 +149,16 @@ class C:
def func(self):
print(self.__foo) # 类内部访问
class D(C):
def show(self):
print(self.__foo) # 派生类中访问
obj = C()
print(obj.__foo) # 通过对象访问 ==> 错误
obj.__foo # 通过对象访问 ==> 错误
obj.func() # 类内部访问 ==> 正确
obj_son = D()
@@ -240,11 +219,11 @@ obj.__add() # 派生类中不能访问
总结:
对于这些私有成员来说,他们只能在类的内部使用,不能类的外部以及派生类中使用.
对于这些私有成员来说,他们只能在类的内部使用,不能类的外部以及派生类中使用.
**ps非要访问私有成员的话可以通过 对象._类__属性名,但是绝对不允许!!!**
为什么可以通过._类__私有成员名访问呢?因为类在创建时,如果遇到了私有成员(包括私有静态字段,私有普通字段,私有方法)它会将其保存在内存时自动在前面加上_类名.
为什么可以通过`._类__私有成员名` 访问呢?因为类在创建时,如果遇到了私有成员(包括私有静态字段,私有普通字段,私有方法)它会将其保存在内存时自动在前面加上_类名.
## 类的其他成员
@@ -487,7 +466,7 @@ print(issubclass(C,A))
思考:那么 list str tuple dict等这些类与 Iterble类 的关系是什么?
```python
from collections import Iterable
from collections.abc import Iterable
print(isinstance([1,2,3], list)) # True
print(isinstance([1,2,3], Iterable)) # True
@@ -495,3 +474,14 @@ print(issubclass(list,Iterable)) # True
# 由上面的例子可得这些可迭代的数据类型list str tuple dict等 都是 Iterable的子类。
```
这种继承关系形成了Python对象模型的闭环object是所有类的基类type是所有类型的基类而type本身又是object的子类。
```python
print(isinstance(object, type))
print(issubclass(type, object))
# object是type的实例因为type创建了object类
# type是object的子类因为所有类都继承自object包括type本身
```

View File

@@ -2,7 +2,13 @@
## 反射
python面向对象中的反射通过字符串的形式操作对象相关的属性。python中的一切事物都是对象都可以使用反射
- python面向对象中的反射
- 指程序在**运行时**动态地获取对象(包括类、模块、实例等)的结构信息(如属性、方法、类型),并能动态地操作这些结构(如调用方法、修改属性、创建对象)的能力。简单来说,反射让程序能在运行时“自省”——了解自身的组成,并根据需要灵活调整行为。
- 反射的常见应用场景
- **动态配置加载**根据配置文件如JSON、YAML动态设置对象属性。例如通过`setattr`将配置中的`debug=True`映射到对象的`debug`属性。
- **插件化架构**:通过`importlib.import_module`动态加载插件模块,再用`getattr`获取插件类的实例并调用其方法。例如,电商系统可动态加载“限时抢购”“团购”等插件订单类。
- **通用工具函数**:编写适用于不同对象的通用工具。例如,`print_object_info`函数通过`dir`获取对象所有属性,再用`getattr`打印属性值。
- **ORM框架**通过反射将数据库表的列映射到Python类的属性。例如Django ORM通过反射获取模型的字段信息动态生成SQL语句。
四个可以实现自省的函数
@@ -35,15 +41,16 @@ func()
print(getattr(obj,'aaaaaaaa','不存在啊')) # 报错
# 设置属性
setattr(obj,'sb',True)
setattr(obj,'show_name',lambda self:self.name+'sb')
setattr(obj,'food','面条')
print(getattr(obj, 'food'))
setattr(obj, 'eat', lambda self: self.name + "在吃" + self.food)
print(obj.__dict__)
print(obj.show_name(obj))
print(obj.eat(obj))
# 删除属性
delattr(obj,'age')
delattr(obj,'show_name')
# delattr(obj,'show_name111') # 不存在,则报错
delattr(obj,'eat')
# delattr(obj,'eat111') # 不存在,则报错
print(obj.__dict__)
```
@@ -161,6 +168,71 @@ while 1:
print('输入错误。。。。')
```
## 元编程特性
**元编程Metaprogramming**是Python中一种高级编程范式其核心思想是**编写能够操作代码本身的程序**——通过在运行时动态生成、修改或执行代码实现对程序行为的灵活控制。这种特性让Python具备极强的动态性与抽象能力成为框架开发、代码生成等场景的基石。
### **1. 装饰器**
**函数/类的行为扩展工具**
装饰器是Python最常用的元编程技术之一本质是**接收函数或类作为输入、返回修改后函数/类的高阶函数**。通过`@decorator`语法糖,可在不修改原代码的情况下,为函数/类添加日志、性能监控、权限验证等功能。
- **基础装饰器**:例如日志装饰器`@log_decorator`,可在函数调用前后打印日志;
- **带参数的装饰器**:通过外层函数接收参数,实现更灵活的功能控制(如`@repeat(times=3)`让函数执行3次
- **类装饰器**用于修改类的行为例如实现单例模式确保类只有一个实例、自动注册类到全局字典如Django模型注册
### **2. 元类**
**类的创建控制器**
元类是**创建类的类**(默认元类为`type`),通过继承`type`并重写`__new__``__init__`方法,可控制类的创建过程,实现动态修改类属性、添加方法、强制类遵循接口规范等功能。
- **动态添加属性/方法**:例如在类创建时自动添加`author`属性或`hello`方法;
- **强制接口检查**:通过元类确保类实现了特定方法(如`run`方法),避免类定义不完整;
- **动态注册类**例如ORM框架中通过元类自动将模型类注册到全局注册表方便后续生成SQL语句。
### **3. 动态属性与描述符**
**属性访问的控制者**
动态属性允许在运行时修改对象的属性,而描述符则通过定义`__get__``__set__`等方法,精确控制属性的访问行为。
- **动态属性**:通过`__getattr__`(获取不存在的属性)、`__setattr__`(设置属性)等方法,实现动态属性访问(如代理类通过`__getattr__`转发属性访问);
- **描述符**:用于实现数据验证、只读属性等功能。例如`ReadOnlyDescriptor`可防止属性被修改,`ValidatedDescriptor`可验证属性值的合法性(如确保年龄为正数)。
### **4. 反射**
**程序的自省能力**
反射是程序**在运行时检查、修改自身结构**的能力,通过内置函数(`getattr``hasattr``setattr``delattr`)和`inspect`模块,可动态获取对象的属性、方法信息,或修改对象行为。
- **获取信息**`hasattr(obj, 'name')`检查对象是否有`name`属性,`getattr(obj, 'name')`获取`name`属性的值;
- **修改属性**`setattr(obj, 'age', 30)`设置对象的`age`属性为30`delattr(obj, 'age')`删除`age`属性;
- **动态调用方法**`getattr(obj, 'method')()`获取并调用对象的`method`方法。
### **5. 动态代码生成与执行**
**运行时代码的灵活构建**
通过`exec``compile``eval`等函数,可在运行时生成并执行代码字符串,实现动态代码生成。
- **动态创建函数**:例如`exec`生成`add`函数(`def add(a, b): return a + b`),并通过`eval`获取函数对象;
- **动态修改方法**猴子补丁Monkey Patching通过动态修改现有类的方法扩展其功能如为`Logger`类动态添加`log_warning`方法);
- **动态生成类**:通过`type`函数动态创建类(如`type('DynamicClass', (), {'attr': 42})`创建包含`attr`属性的类)。
### **6. AST操作**
**代码结构的深度修改**
`ast`抽象语法树模块允许解析、修改Python代码的语法结构实现更高级的代码生成与修改。
- **解析代码**将代码字符串解析为AST`ast.parse("a = 1 + 2")`
- **修改AST**遍历AST节点修改代码结构如将`a = 1 + 2`修改为`a = 1 * 2`
- **生成代码**将修改后的AST编译为可执行代码`compile`函数)。
元编程的灵活性使其成为Python框架如Django、Flask、SQLAlchemy的核心技术但也需注意**代码可读性**(过度使用元编程会增加代码复杂度)、**调试难度**(动态生成的代码难以跟踪)、**安全性**(动态执行代码可能引发安全漏洞)等问题。合理使用元编程,能让代码更简洁、灵活,提升开发效率。
## 函数 vs 方法
### 通过打印函数(方法)名确定
@@ -218,7 +290,7 @@ class A:
pass
@staticmethod
def func2(self):
def func2():
pass
@@ -241,11 +313,11 @@ print(isinstance(obj.func2,FunctionType))
4. 方法可以操作类内部的数据。
5. 方法跟对象是关联的。如我们在用strip()方法是不是都是要通过str对象调用比如我们有字符串s,然后s.strip()这样调用。是的strip()方法属于str对象。
5. 方法跟对象是关联的。如我们在用strip()方法是不是都是要通过str对象调用比如我们有字符串s,然后s.strip()这样调用strip()方法属于str对象。
我们或许在日常中会口语化称呼函数和方法时不严谨,但是我们心中要知道二者之间的区别。
在其他语言中如Java中只有方法C中只有函数C++么,则取决于是否在类中
在其他语言中如Java中只有方法C中只有函数C++则取决于是否在类中
## 双下方法
@@ -409,14 +481,14 @@ class A:
```python
class Foo:
def __init__(self,name):
self.name=name
def __init__(self, name):
self.name = name
def __getitem__(self, item):
print(self.__dict__[item])
def __setitem__(self, key, value):
self.__dict__[key]=value
self.__dict__[key] = value
print('赋值成功')
def __delitem__(self, key):
@@ -427,12 +499,13 @@ class Foo:
print('del obj.key时,我执行')
self.__dict__.pop(item)
f1=Foo('sb')
f1['age']=18
f1['age1']=19
f1 = Foo('张三')
f1['age'] = 18
f1['age1'] = 19
del f1.age1
del f1['age']
f1['name']='mingzi'
f1['name'] = '李四'
print(f1.__dict__)
```
@@ -477,8 +550,9 @@ class Diycontextor:
self.filehander.close()
with Diycontextor('config', 'r') as f:
for i in f:
with Diycontextor('config', 'a+') as f:
f.seek(0)
for i in f.readlines():
print(i.strip())
```
@@ -539,16 +613,16 @@ class RoleConfig(StarkConfig):
class AdminSite:
def __init__(self):
self._registry = {}
self.registry_db = {}
def register(self, k, v):
self._registry[k] = v
self.registry_db[k] = v
site = AdminSite()
site.register(UserInfo, StarkConfig)
# 1
obj = site._registry[UserInfo]()
obj = site.registry_db[UserInfo](100)
# 2
# obj = site._registry[UserInfo](100)
@@ -585,11 +659,15 @@ class AdminSite:
def register(self,k,v):
self._registry[k] = v(k)
@property
def registry_db(self):
return self._registry
site = AdminSite()
site.register(UserInfo,StarkConfig)
site.register(Department,RoleConfig)
for k,row in site._registry.items():
for k,row in site.registry_db.items():
row.run()
```

Binary file not shown.

View File

@@ -215,6 +215,7 @@ import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.bind(('127.0.0.1',8080))
phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
phone.listen(5)
while 1:
@@ -222,16 +223,16 @@ while 1:
print(conn,client_addr,sep='\n')
while 1:
try:
if conn:
from_client_data = conn.recv(1024)
if len(from_client_data) == 0 or from_client_data.decode('utf-8') == 'q':
# 如果客户端返回为空或者q说明已经断开
break
print(from_client_data.decode('utf-8'))
conn.send(from_client_data.upper())
except:
else:
break
conn.close()
phone.close()
```
客户端
@@ -244,9 +245,11 @@ phone.connect(('127.0.0.1',8080))
while 1:
client_data = input('>>> ')
if len(client_data.strip()) == 0:
continue
phone.send(client_data.encode('utf-8'))
if client_data == 'q':break
if client_data == 'q':
break
from_server_data = phone.recv(1024)
print(from_server_data.decode('utf-8'))
@@ -550,6 +553,67 @@ phone.close()
## 粘包的解决方案
### 添加结束字符
在每次发送一个信息结束的地方,添加一个标识,在从缓冲区获取数据时候,根据表示来判断消息是否已经获取结束
- 服务端
```python
import socket
import subprocess
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
phone.bind(('127.0.0.1', 8080))
phone.listen(5)
while 1: # 循环连接客户端
conn, client_addr = phone.accept()
print(client_addr)
while 1:
try:
cmd = conn.recv(1024)
ret = subprocess.Popen(cmd.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
correct_msg = ret.stdout.read()
error_msg = ret.stderr.read()
conn.send(correct_msg + error_msg + "結束".encode("gbk"))
except ConnectionResetError:
break
conn.close()
phone.close()
```
- 客户端
```python
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 买电话
phone.connect(('127.0.0.1',8080)) # 与客户端建立连接, 拨号
while 1:
cmd = input('>>>')
phone.send(cmd.encode('utf-8'))
from_server_data = b""
while True:
from_server_data += phone.recv(1024)
if from_server_data.decode('gbk').count("結束") > 0:
break
print(from_server_data.decode('gbk'))
phone.close()
```
- 这样只是解决了一次消息没有收完整的情况但是一次接受1024可能会将紧跟的下一条消息的开头也一并接收了
### struct模块
该模块可以把一个类型如数字转成固定长度的bytes
@@ -567,6 +631,8 @@ ret1 = struct.unpack('i',ret)[0]
print(ret1, type(ret1), len(ret1))
# 但是通过struct 处理不能处理太大
# 可处理的范围是 -2,147,483,648 ~ 2,147,483,647即 -2³¹ ~ 2³¹-1
# 如果超出范围就会发生异常struct.error
```
方案一:
@@ -640,7 +706,12 @@ while 1:
res = b''
while recv_size < total_size:
recv_data = phone.recv(1024)
# 精准的获取数据的长度,防止将后面跟着的数据头部获取到
if (total_size - recv_size) > 1024:
recv_buffer = 1024
else:
recv_buffer = total_size - recv_size
recv_data = phone.recv(recv_buffer)
res += recv_data
recv_size += len(recv_data)
@@ -754,13 +825,19 @@ while 1:
res = b''
while recv_size < total_size:
recv_data = phone.recv(1024)
# 精准的获取数据的长度,防止将后面跟着的数据头部获取到
if (total_size - recv_size) > 1024:
recv_buffer = 1024
else:
recv_buffer = total_size - recv_size
recv_data = phone.recv(recv_buffer)
res += recv_data
recv_size += len(recv_data)
print(res.decode('gbk'))
phone.close()
```
FTP上传下载文件的代码简单版
@@ -772,7 +849,6 @@ import socket
import struct
import json
sk = socket.socket()
## buffer = 4096 # 当双方的这个接收发送的大小比较大的时候就像这个4096就会丢数据这个等我查一下再告诉大家改小了就ok的在linux上也是ok的。
buffer = 1024 #每次接收数据的大小
sk.bind(('127.0.0.1',8090))
sk.listen()
@@ -791,9 +867,10 @@ with open(head['filename'],'wb') as f:
f.write(content)
filesize -= buffer
else:
content = conn.recv(buffer)
content = conn.recv(filesize)
f.write(content)
break
print(head['filename'], "接收成功")
conn.close()
sk.close()
@@ -810,15 +887,14 @@ sk = socket.socket()
sk.connect(('127.0.0.1',8090))
buffer = 1024 #读取文件的时候,每次读取的大小
head = {
'filepath':r'C:\Users\Aaron\Desktop\新建文件夹', #需要下载的文件路径,也就是文件所在的文件夹
'filename':'config', #改成上面filepath下的一个文件
'filepath':r'C:\Users\simid\Desktop', #需要下载的文件路径,也就是文件所在的文件夹
'filename':'KKRIEGER.EXE', #改成上面filepath下的一个文件
'filesize':None,
}
file_path = os.path.join(head['filepath'],head['filename'])
filesize = os.path.getsize(file_path)
head['filesize'] = filesize
# json_head = json.dumps(head,ensure_ascii=False) #字典转换成字符串
json_head = json.dumps(head) #字典转换成字符串
bytes_head = json_head.encode('utf-8') #字符串转换成bytes类型
print(json_head)

View File

@@ -8,6 +8,8 @@
![image-20210725220917981](02.%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%8F%91%E5%B1%95%E5%8F%B2/image-20210725220917981.png)
程序员将对应于程序和数据的已穿孔的纸带(或卡片)装入输入机,然后启动输入机把程序和数据输入计算机内存,接着通过控制台开关启动程序针对数据运行;计算完毕,打印机输出计算结果;用户取走结果并卸下纸带(或卡片)后,才让下一个用户上机。
手工操作方式两个特点:
@@ -87,8 +89,12 @@
![image-20210725221001607](02.%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%8F%91%E5%B1%95%E5%8F%B2/image-20210725221001607.png)
![image-20210725221010282](02.%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%8F%91%E5%B1%95%E5%8F%B2/image-20210725221010282.png)
分时技术把处理机的运行时间分成很短的时间片按时间片轮流把处理机分配给各联机作业使用
若某个作业在分配给它的时间片内不能完成其计算则该作业暂时中断把处理机让给另一作业使用等待下一轮时再继续其运行由于计算机速度很快作业运行轮转得很快给每个用户的印象是好象他独占了一台计算机而每个用户可以通过自己的终端向系统发出各种操作控制命令在充分的人机交互情况下完成作业的运行
具有上述特征的计算机系统称为分时系统它允许多个用户同时联机使用计算机

View File

@@ -71,7 +71,7 @@
### 状态介绍
![image-20210725221132043](03.%E5%A4%9A%E8%BF%9B%E7%A8%8B/image-20210725221132043.png)
![image-20250918143803006](03.多进程/image-20250918143803006.png)
在了解其他概念之前,我们首先要了解进程的几个状态。在程序运行的过程中,由于被操作系统的调度算法控制,程序会进入几个状态:就绪,运行和阻塞。
@@ -172,8 +172,9 @@ process模块是一个创建进程的模块借助这个模块就可以完
方法介绍
| p.start() | 启动进程并调用该子进程中的p.run() |
| 方法 | 描述 |
| ----------------- | ------------------------------------------------------------ |
| p.start() | 启动进程并调用该子进程中的p.run() |
| p.run() | 进程启动时运行的方法正是它去调用target指定的函数我们自定义类的类中一定要实现该方法 |
| p.terminate() | 强制终止进程p不会进行任何清理操作如果p创建了子进程该子进程就成了僵尸进程使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放进而导致死锁 |
| p.is_alive() | 如果p仍然运行返回True |
@@ -181,8 +182,9 @@ process模块是一个创建进程的模块借助这个模块就可以完
属性介绍
| p.daemon | 默认值为False如果设为True代表p为后台运行的守护进程当p的父进程终止时p也随之终止并且设定为True后p不能创建自己的新进程必须在p.start()之前设置 |
| 方法 | 描述 |
| ---------- | ------------------------------------------------------------ |
| p.daemon | 默认值为False如果设为True代表p为后台运行的守护进程当p的父进程终止时p也随之终止并且设定为True后p不能创建自己的新进程必须在p.start()之前设置 |
| p.name | 进程的名称 |
| p.pid | 进程的pid |
| p.exitcode | 进程在运行时为None、如果为N表示被信号N结束(了解即可) |
@@ -209,7 +211,7 @@ if __name__ == '__main__':
print('主程序')
```
使用join方法
使用join方法,此方法会等待子进程结束
```python
import time
@@ -318,9 +320,9 @@ class MyProcess(Process):
print('%s 正在和女主播聊天' %self.name)
if __name__ == '__main__':
p1 = MyProcess('陈松')
p2 = MyProcess('松哥')
p3 = MyProcess('松松')
p1 = MyProcess('张三')
p2 = MyProcess('李四')
p3 = MyProcess('王五')
p1.start()
p2.start()
@@ -375,7 +377,7 @@ class Myprocess(Process):
print('%s正在和女主播聊天' %self.person)
if __name__ == '__main__':
p=Myprocess('陈松')
p=Myprocess('张三')
p.daemon=True #一定要在p.start()前设置,设置p为守护进程,禁止p创建子进程,并且父进程代码执行结束,p即终止运行
p.start()
time.sleep(10) # 在sleep时查看进程id对应的进程
@@ -467,12 +469,12 @@ class Myprocess(Process):
super().__init__()
def run(self):
print('%s正在和陈松聊天' %self.name)
print('%s正在和张三聊天' %self.name)
time.sleep(random.randrange(1,5))
print('%s还在和陈松聊天' %self.name)
print('%s还在和张三聊天' %self.name)
if __name__ == '__main__':
p1=Myprocess('陈松')
p1=Myprocess('李四')
p1.start()
p1.terminate() # 关闭进程,不会立即关闭,所以is_alive立刻查看的结果可能还是存活
@@ -501,7 +503,7 @@ class Myprocess(Process):
# print('%s正在和网红脸聊天' %self.person)
if __name__ == '__main__':
p1=Myprocess('陈松')
p1=Myprocess('张三')
p1.start()
print(p1.pid) #可以查看子进程的进程id
```
@@ -581,7 +583,7 @@ if __name__ == '__main__':
p.start()
```
来保护票
来保护票
```python
#文件db的内容为{"count":1}

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

View File

@@ -31,7 +31,7 @@
### 使用线程的实际场景
开启一个字处理软件进程,该进程肯定需要办不止一件事情,比如监听键盘输入,处理文字,定时自动将文字保存到硬盘,这三个任务操作的都是同一块数据,因而不能用多进程。只能在一个进程里并发地开启三个线程,如果是单线程,那就只能是,键盘输入时,不能处理文字和自动保存,自动保存时又不能输入和处理文字。
开启一个软件进程,该进程肯定需要办不止一件事情,比如监听键盘输入,处理文字,定时自动将文字保存到硬盘,这三个任务操作的都是同一块数据,因而不能用多进程。只能在一个进程里并发地开启三个线程,如果是单线程,那就只能是,键盘输入时,不能处理文字和自动保存,自动保存时又不能输入和处理文字。
### 内存中的线程
@@ -50,9 +50,9 @@
### 全局解释器锁GIL
Python代码的执行由Python虚拟机(也叫解释器主循环)来控制。Python在设计之初就考虑到要在主循环中同时只有一个线程在执行。虽然 Python 解释器中可以“运行”多个线程,但在任意时刻只有一个线程在解释器中运行。
  对Python虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个线程在运行。
对Python虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个线程在运行。
  在多线程环境中Python 虚拟机按以下方式执行:
在多线程环境中Python 虚拟机按以下方式执行:
1. 设置 GIL
@@ -65,7 +65,8 @@ Python代码的执行由Python虚拟机(也叫解释器主循环)来控制。Pyt
5. 解锁 GIL
6. 再次重复以上所有步骤。
在调用外部代码(如 C/C++扩展函数)的时候GIL将会被锁定直到这个函数结束为止(由于在这期间没有Python的字节码被运行所以不会做线程切换)编写扩展的程序员可以主动解锁GIL。
在调用外部代码(如 C/C++扩展函数)的时候GIL将会被锁定直到这个函数结束为止(由于在这期间没有Python的字节码被运行所以不会做线程切换)编写扩展的程序可以主动解锁GIL。
### python线程模块的选择
@@ -87,7 +88,7 @@ def sayhi(name):
print('%s say hello' %name)
if __name__ == '__main__':
t=Thread(target=sayhi,args=('aaron',))
t=Thread(target=sayhi,args=('张三',))
t.start()
print('主线程')
```
@@ -107,7 +108,7 @@ class Sayhi(Thread):
if __name__ == '__main__':
t = Sayhi('aaron')
t = Sayhi('张三')
t.start()
print('主线程')
```
@@ -256,7 +257,7 @@ import os
def work():
import time
time.sleep(3)
print(threading.current_thread().getName())
print(threading.current_thread().name)
if __name__ == '__main__':
@@ -264,7 +265,7 @@ if __name__ == '__main__':
t=Thread(target=work)
t.start()
print(threading.current_thread().getName())
print(threading.current_thread().name)
print(threading.current_thread()) #主线程
print(threading.enumerate()) #连同主线程在内有两个运行的线程
print(threading.active_count())
@@ -281,7 +282,7 @@ def sayhi(name):
print('%s say hello' %name)
if __name__ == '__main__':
t=Thread(target=sayhi,args=('aaron',))
t=Thread(target=sayhi,args=('张三',))
t.start()
t.join()
print('主线程')
@@ -305,8 +306,8 @@ def sayhi(name):
print('%s say hello' %name)
if __name__ == '__main__':
t=Thread(target=sayhi,args=('aaron',))
t.setDaemon(True) #必须在t.start()之前设置
t=Thread(target=sayhi,args=('张三',))
t.daemon = True #必须在t.start()之前设置
t.start()
print('主线程')
@@ -433,8 +434,7 @@ from threading import current_thread,Thread,Lock
import os,time
def task():
#未加锁的代码并发运行
time.sleep(3)
print('%s start to run' %current_thread().getName())
print('%s start to run' %current_thread().name)
global n
#加锁的代码串行运行
lock.acquire()
@@ -459,34 +459,10 @@ if __name__ == '__main__':
```
有的同学可能有疑问:既然加锁会让运行变成串行,那么我在start之后立即使用join,就不用加锁了啊,也是串行的效果啊
没错:在start之后立刻使用jion,肯定会将100个任务的执行变成串行,毫无疑问,最终n的结果也肯定是0,是安全的,但问题是
没错:在start之后立刻使用join,肯定会将100个任务的执行变成串行,毫无疑问,最终n的结果也肯定是0,是安全的,但问题是
start后立即join:任务内的所有代码都是串行执行的,而加锁,只是加锁的部分即修改共享数据的部分是串行的
单从保证数据安全方面,二者都可以实现,但很明显是加锁的效率更高.
```python
from threading import current_thread,Thread,Lock
import os,time
def task():
time.sleep(3)
print('%s start to run' %current_thread().getName())
global n
temp=n
time.sleep(0.5)
n=temp-1
if __name__ == '__main__':
n=100
lock=Lock()
start_time=time.time()
for i in range(100):
t=Thread(target=task)
t.start()
t.join()
stop_time=time.time()
print('主:%s n:%s' %(stop_time-start_time,n))
```
### 死锁与递归锁
两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为**死锁进程**

View File

@@ -127,7 +127,7 @@ from greenlet import greenlet
def eat(name):
print('%s eat 1' %name)
g2.switch('aaron')
g2.switch('张三')
print('%s eat 2' %name)
g2.switch()
def play(name):
@@ -138,7 +138,7 @@ def play(name):
g1=greenlet(eat)
g2=greenlet(play)
g1.switch('aaron') # 可以在第一次switch时传入参数以后都不需要
g1.switch('张三') # 可以在第一次switch时传入参数以后都不需要
```
单纯的切换在没有io的情况下或者没有重复开辟内存空间的操作反而会降低程序的执行速度
@@ -224,8 +224,8 @@ def play(name):
print('%s play 2' %name)
g1=gevent.spawn(eat,'aaron')
g2=gevent.spawn(play,name='aaron')
g1=gevent.spawn(eat,'张三')
g2=gevent.spawn(play,name='张三')
g1.join()
g2.join()
#或者gevent.joinall([g1,g2])
@@ -259,7 +259,7 @@ gevent.joinall([g1,g2])
print('主')
```
用threading.current_thread().getName()来查看每个g1和g2查看的结果为DummyThread-n即假线程
用threading.current_thread().name来查看每个g1和g2查看的结果为DummyThread-n即假线程
```python
from gevent import monkey;monkey.patch_all()
@@ -267,13 +267,13 @@ import threading
import gevent
import time
def eat():
print(threading.current_thread().getName())
print(threading.current_thread().name)
print('eat food 1')
time.sleep(2)
print('eat food 2')
def play():
print(threading.current_thread().getName())
print(threading.current_thread().name)
print('play 1')
time.sleep(1)
print('play 2')
@@ -372,6 +372,8 @@ def talk(conn,addr):
try:
while True:
res=conn.recv(1024)
if len(res) == 0:
continue
print('client %s:%s msg: %s' %(addr[0],addr[1],res))
conn.send(res.upper())
except Exception as e:
@@ -389,7 +391,7 @@ if __name__ == '__main__':
from socket import *
client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080))
client.connect(('127.0.0.1',8088))
while True:
@@ -414,7 +416,7 @@ def client(server_ip,port):
count=0
while True:
c.send(('%s say hello %s' %(threading.current_thread().getName(),count)).encode('utf-8'))
c.send(('%s say hello %s' %(threading.current_thread().name,count)).encode('utf-8'))
msg=c.recv(1024)
print(msg.decode('utf-8'))
count+=1