Compare commits
17 Commits
c09e949cd3
...
main
Author | SHA1 | Date | |
---|---|---|---|
bcfc9e15b5 | |||
4f9f49a2e0 | |||
7b53b37b3b | |||
836df0d56c | |||
df099c7f1a | |||
ef0ed27b9e | |||
66148187d0 | |||
244627cf69 | |||
3ed89009e5 | |||
4222354358 | |||
ed1ace678b | |||
d5f0bd6570 | |||
47e3b9a068 | |||
355a5a52f3 | |||
36ca88991e | |||
4d74d5ea44 | |||
44510de885 |
@@ -65,12 +65,12 @@ import time
|
|||||||
def timer(func):
|
def timer(func):
|
||||||
def inner(*args,**kwargs):
|
def inner(*args,**kwargs):
|
||||||
start = time.time()
|
start = time.time()
|
||||||
func(args,kwargs)
|
func(*args,**kwargs)
|
||||||
print(time.time() - start)
|
print(time.time() - start)
|
||||||
return inner
|
return inner
|
||||||
@timer
|
@timer
|
||||||
def func1(*args,**kwargs):
|
def func1(*args,**kwargs):
|
||||||
print(args,kwargs)
|
print(*args,**kwargs)
|
||||||
func1('hello world','abc',123,432)
|
func1('hello world','abc',123,432)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@@ -14,7 +14,7 @@ variable = [out_exp_res for out_exp in input_list if out_exp == 2]
|
|||||||
30以内所有能被3整除的数
|
30以内所有能被3整除的数
|
||||||
|
|
||||||
```python
|
```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)
|
print(multiples)
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ print(multiples)
|
|||||||
```python
|
```python
|
||||||
def squared(x):
|
def squared(x):
|
||||||
return x*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)
|
print(multiples)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@@ -79,7 +79,7 @@ for i in range(n):
|
|||||||
说明:这段代码,for循环 里面的代码会执行n遍,因此它消耗的时间是随着n的变化而变
|
说明:这段代码,for循环 里面的代码会执行n遍,因此它消耗的时间是随着n的变化而变
|
||||||
化的,因此这类代码都可以用O(n)来表示它的时间复杂度
|
化的,因此这类代码都可以用O(n)来表示它的时间复杂度
|
||||||
|
|
||||||
## 线性对数阶 O(nlogN)
|
## 线性对数阶 O($$nlogN$$)
|
||||||
|
|
||||||
```python
|
```python
|
||||||
n = 100
|
n = 100
|
||||||
@@ -102,7 +102,7 @@ for i in range(n):
|
|||||||
j += i
|
j += i
|
||||||
```
|
```
|
||||||
说明:平方阶$$O(n2)$$就更容易理解了,如果把$$O(n)$$的代码再嵌套循环一遍,它的时间复杂度就是$$O(n^2)$$,这段代码其实就是嵌套了2层n循环,它的时间复杂度就是$$O(n*n)$$,即$$O(n^2)$$ 如果将其中一层循环的n改成m,那它的时间复杂度就变成了$$O(m*n)$$
|
说明:平方阶$$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 循环,其它的类似
|
说明:参考上面的 O(n²) 去理解就好了,O(n³)相当于三层 n 循环,其它的类似
|
||||||
|
|
||||||
|
@@ -71,12 +71,12 @@ class C:
|
|||||||
name = "公有静态字段"
|
name = "公有静态字段"
|
||||||
|
|
||||||
def func(self):
|
def func(self):
|
||||||
print (C.name)
|
print(C.name)
|
||||||
|
|
||||||
class D(C):
|
class D(C):
|
||||||
|
|
||||||
def show(self):
|
def show(self):
|
||||||
print (C.name)
|
print(C.name)
|
||||||
|
|
||||||
|
|
||||||
print(C.name) # 类访问
|
print(C.name) # 类访问
|
||||||
@@ -94,12 +94,12 @@ class C:
|
|||||||
__name = "私有静态字段"
|
__name = "私有静态字段"
|
||||||
|
|
||||||
def func(self):
|
def func(self):
|
||||||
print (C.__name)
|
print(C.__name)
|
||||||
|
|
||||||
class D(C):
|
class D(C):
|
||||||
|
|
||||||
def show(self):
|
def show(self):
|
||||||
print (C.__name)
|
print(C.__name)
|
||||||
|
|
||||||
|
|
||||||
print(C.__name) # 不可在外部访问
|
print(C.__name) # 不可在外部访问
|
||||||
@@ -147,39 +147,18 @@ class C:
|
|||||||
self.__foo = "私有字段"
|
self.__foo = "私有字段"
|
||||||
|
|
||||||
def func(self):
|
def func(self):
|
||||||
print self.foo # 类内部访问
|
print(self.__foo) # 类内部访问
|
||||||
|
|
||||||
|
|
||||||
class D(C):
|
class D(C):
|
||||||
|
|
||||||
def show(self):
|
def show(self):
|
||||||
print self.foo # 派生类中访问
|
print(self.__foo) # 派生类中访问
|
||||||
|
|
||||||
|
|
||||||
obj = C()
|
obj = C()
|
||||||
|
|
||||||
obj.__foo # 通过对象访问 ==> 错误
|
obj.__foo # 通过对象访问 ==> 错误
|
||||||
obj.func() # 类内部访问 ==> 正确
|
|
||||||
|
|
||||||
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()
|
|
||||||
|
|
||||||
print(obj.__foo) # 通过对象访问 ==> 错误
|
|
||||||
obj.func() # 类内部访问 ==> 正确
|
obj.func() # 类内部访问 ==> 正确
|
||||||
|
|
||||||
obj_son = D()
|
obj_son = D()
|
||||||
@@ -240,11 +219,11 @@ obj.__add() # 派生类中不能访问
|
|||||||
|
|
||||||
总结:
|
总结:
|
||||||
|
|
||||||
对于这些私有成员来说,他们只能在类的内部使用,不能再类的外部以及派生类中使用.
|
对于这些私有成员来说,他们只能在类的内部使用,不能在类的外部以及派生类中使用.
|
||||||
|
|
||||||
**ps:非要访问私有成员的话,可以通过 对象._类__属性名,但是绝对不允许!!!**
|
**ps:非要访问私有成员的话,可以通过 对象._类__属性名,但是绝对不允许!!!**
|
||||||
|
|
||||||
为什么可以通过._类__私有成员名访问呢?因为类在创建时,如果遇到了私有成员(包括私有静态字段,私有普通字段,私有方法)它会将其保存在内存时自动在前面加上_类名.
|
为什么可以通过`._类__私有成员名` 访问呢?因为类在创建时,如果遇到了私有成员(包括私有静态字段,私有普通字段,私有方法)它会将其保存在内存时自动在前面加上_类名.
|
||||||
|
|
||||||
## 类的其他成员
|
## 类的其他成员
|
||||||
|
|
||||||
@@ -487,7 +466,7 @@ print(issubclass(C,A))
|
|||||||
思考:那么 list str tuple dict等这些类与 Iterble类 的关系是什么?
|
思考:那么 list str tuple dict等这些类与 Iterble类 的关系是什么?
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from collections import Iterable
|
from collections.abc import Iterable
|
||||||
|
|
||||||
print(isinstance([1,2,3], list)) # True
|
print(isinstance([1,2,3], list)) # True
|
||||||
print(isinstance([1,2,3], Iterable)) # True
|
print(isinstance([1,2,3], Iterable)) # True
|
||||||
@@ -495,3 +474,14 @@ print(issubclass(list,Iterable)) # True
|
|||||||
|
|
||||||
# 由上面的例子可得,这些可迭代的数据类型,list str tuple dict等 都是 Iterable的子类。
|
# 由上面的例子可得,这些可迭代的数据类型,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本身)。
|
||||||
|
```
|
||||||
|
|
||||||
|
@@ -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','不存在啊')) # 报错
|
print(getattr(obj,'aaaaaaaa','不存在啊')) # 报错
|
||||||
|
|
||||||
# 设置属性
|
# 设置属性
|
||||||
setattr(obj,'sb',True)
|
setattr(obj,'food','面条')
|
||||||
setattr(obj,'show_name',lambda self:self.name+'sb')
|
print(getattr(obj, 'food'))
|
||||||
|
setattr(obj, 'eat', lambda self: self.name + "在吃" + self.food)
|
||||||
print(obj.__dict__)
|
print(obj.__dict__)
|
||||||
print(obj.show_name(obj))
|
print(obj.eat(obj))
|
||||||
|
|
||||||
# 删除属性
|
# 删除属性
|
||||||
delattr(obj,'age')
|
delattr(obj,'age')
|
||||||
delattr(obj,'show_name')
|
delattr(obj,'eat')
|
||||||
# delattr(obj,'show_name111') # 不存在,则报错
|
# delattr(obj,'eat111') # 不存在,则报错
|
||||||
|
|
||||||
print(obj.__dict__)
|
print(obj.__dict__)
|
||||||
```
|
```
|
||||||
@@ -161,6 +168,71 @@ while 1:
|
|||||||
print('输入错误。。。。')
|
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 方法
|
## 函数 vs 方法
|
||||||
|
|
||||||
### 通过打印函数(方法)名确定
|
### 通过打印函数(方法)名确定
|
||||||
@@ -218,7 +290,7 @@ class A:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def func2(self):
|
def func2():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@@ -241,11 +313,11 @@ print(isinstance(obj.func2,FunctionType))
|
|||||||
|
|
||||||
4. 方法可以操作类内部的数据。
|
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
|
```python
|
||||||
class Foo:
|
class Foo:
|
||||||
def __init__(self,name):
|
def __init__(self, name):
|
||||||
self.name=name
|
self.name = name
|
||||||
|
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
print(self.__dict__[item])
|
print(self.__dict__[item])
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
self.__dict__[key]=value
|
self.__dict__[key] = value
|
||||||
print('赋值成功')
|
print('赋值成功')
|
||||||
|
|
||||||
def __delitem__(self, key):
|
def __delitem__(self, key):
|
||||||
@@ -427,12 +499,13 @@ class Foo:
|
|||||||
print('del obj.key时,我执行')
|
print('del obj.key时,我执行')
|
||||||
self.__dict__.pop(item)
|
self.__dict__.pop(item)
|
||||||
|
|
||||||
f1=Foo('sb')
|
|
||||||
f1['age']=18
|
f1 = Foo('张三')
|
||||||
f1['age1']=19
|
f1['age'] = 18
|
||||||
|
f1['age1'] = 19
|
||||||
del f1.age1
|
del f1.age1
|
||||||
del f1['age']
|
del f1['age']
|
||||||
f1['name']='mingzi'
|
f1['name'] = '李四'
|
||||||
print(f1.__dict__)
|
print(f1.__dict__)
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -477,8 +550,9 @@ class Diycontextor:
|
|||||||
self.filehander.close()
|
self.filehander.close()
|
||||||
|
|
||||||
|
|
||||||
with Diycontextor('config', 'r') as f:
|
with Diycontextor('config', 'a+') as f:
|
||||||
for i in f:
|
f.seek(0)
|
||||||
|
for i in f.readlines():
|
||||||
print(i.strip())
|
print(i.strip())
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -539,16 +613,16 @@ class RoleConfig(StarkConfig):
|
|||||||
class AdminSite:
|
class AdminSite:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._registry = {}
|
self.registry_db = {}
|
||||||
|
|
||||||
def register(self, k, v):
|
def register(self, k, v):
|
||||||
self._registry[k] = v
|
self.registry_db[k] = v
|
||||||
|
|
||||||
|
|
||||||
site = AdminSite()
|
site = AdminSite()
|
||||||
site.register(UserInfo, StarkConfig)
|
site.register(UserInfo, StarkConfig)
|
||||||
# 1
|
# 1
|
||||||
obj = site._registry[UserInfo]()
|
obj = site.registry_db[UserInfo](100)
|
||||||
|
|
||||||
# 2
|
# 2
|
||||||
# obj = site._registry[UserInfo](100)
|
# obj = site._registry[UserInfo](100)
|
||||||
@@ -585,11 +659,15 @@ class AdminSite:
|
|||||||
def register(self,k,v):
|
def register(self,k,v):
|
||||||
self._registry[k] = v(k)
|
self._registry[k] = v(k)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def registry_db(self):
|
||||||
|
return self._registry
|
||||||
|
|
||||||
site = AdminSite()
|
site = AdminSite()
|
||||||
site.register(UserInfo,StarkConfig)
|
site.register(UserInfo,StarkConfig)
|
||||||
site.register(Department,RoleConfig)
|
site.register(Department,RoleConfig)
|
||||||
|
|
||||||
for k,row in site._registry.items():
|
for k,row in site.registry_db.items():
|
||||||
row.run()
|
row.run()
|
||||||
```
|
```
|
||||||
|
|
||||||
|
BIN
02.面向对象/代码生成式游戏/KKRIEGER.EXE
Normal file
BIN
02.面向对象/代码生成式游戏/KKRIEGER.EXE
Normal file
Binary file not shown.
@@ -215,6 +215,7 @@ import socket
|
|||||||
|
|
||||||
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
|
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
|
||||||
phone.bind(('127.0.0.1',8080))
|
phone.bind(('127.0.0.1',8080))
|
||||||
|
phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
phone.listen(5)
|
phone.listen(5)
|
||||||
|
|
||||||
while 1:
|
while 1:
|
||||||
@@ -222,16 +223,16 @@ while 1:
|
|||||||
print(conn,client_addr,sep='\n')
|
print(conn,client_addr,sep='\n')
|
||||||
|
|
||||||
while 1:
|
while 1:
|
||||||
try:
|
if conn:
|
||||||
from_client_data = conn.recv(1024)
|
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'))
|
print(from_client_data.decode('utf-8'))
|
||||||
|
|
||||||
conn.send(from_client_data.upper())
|
conn.send(from_client_data.upper())
|
||||||
except:
|
else:
|
||||||
break
|
break
|
||||||
|
|
||||||
conn.close()
|
|
||||||
phone.close()
|
|
||||||
```
|
```
|
||||||
|
|
||||||
客户端
|
客户端
|
||||||
@@ -244,9 +245,11 @@ phone.connect(('127.0.0.1',8080))
|
|||||||
|
|
||||||
while 1:
|
while 1:
|
||||||
client_data = input('>>> ')
|
client_data = input('>>> ')
|
||||||
|
if len(client_data.strip()) == 0:
|
||||||
|
continue
|
||||||
phone.send(client_data.encode('utf-8'))
|
phone.send(client_data.encode('utf-8'))
|
||||||
if client_data == 'q':break
|
if client_data == 'q':
|
||||||
|
break
|
||||||
from_server_data = phone.recv(1024)
|
from_server_data = phone.recv(1024)
|
||||||
print(from_server_data.decode('utf-8'))
|
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模块
|
### struct模块
|
||||||
|
|
||||||
该模块可以把一个类型,如数字,转成固定长度的bytes
|
该模块可以把一个类型,如数字,转成固定长度的bytes
|
||||||
@@ -567,6 +631,8 @@ ret1 = struct.unpack('i',ret)[0]
|
|||||||
print(ret1, type(ret1), len(ret1))
|
print(ret1, type(ret1), len(ret1))
|
||||||
|
|
||||||
# 但是通过struct 处理不能处理太大
|
# 但是通过struct 处理不能处理太大
|
||||||
|
# 可处理的范围是 -2,147,483,648 ~ 2,147,483,647(即 -2³¹ ~ 2³¹-1)。
|
||||||
|
# 如果超出范围,就会发生异常,struct.error
|
||||||
```
|
```
|
||||||
|
|
||||||
方案一:
|
方案一:
|
||||||
@@ -640,7 +706,12 @@ while 1:
|
|||||||
res = b''
|
res = b''
|
||||||
|
|
||||||
while recv_size < total_size:
|
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
|
res += recv_data
|
||||||
recv_size += len(recv_data)
|
recv_size += len(recv_data)
|
||||||
|
|
||||||
@@ -754,13 +825,19 @@ while 1:
|
|||||||
res = b''
|
res = b''
|
||||||
|
|
||||||
while recv_size < total_size:
|
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
|
res += recv_data
|
||||||
recv_size += len(recv_data)
|
recv_size += len(recv_data)
|
||||||
|
|
||||||
print(res.decode('gbk'))
|
print(res.decode('gbk'))
|
||||||
|
|
||||||
phone.close()
|
phone.close()
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
FTP上传下载文件的代码(简单版)
|
FTP上传下载文件的代码(简单版)
|
||||||
@@ -772,7 +849,6 @@ import socket
|
|||||||
import struct
|
import struct
|
||||||
import json
|
import json
|
||||||
sk = socket.socket()
|
sk = socket.socket()
|
||||||
## buffer = 4096 # 当双方的这个接收发送的大小比较大的时候,就像这个4096,就会丢数据,这个等我查一下再告诉大家,改小了就ok的,在linux上也是ok的。
|
|
||||||
buffer = 1024 #每次接收数据的大小
|
buffer = 1024 #每次接收数据的大小
|
||||||
sk.bind(('127.0.0.1',8090))
|
sk.bind(('127.0.0.1',8090))
|
||||||
sk.listen()
|
sk.listen()
|
||||||
@@ -791,9 +867,10 @@ with open(head['filename'],'wb') as f:
|
|||||||
f.write(content)
|
f.write(content)
|
||||||
filesize -= buffer
|
filesize -= buffer
|
||||||
else:
|
else:
|
||||||
content = conn.recv(buffer)
|
content = conn.recv(filesize)
|
||||||
f.write(content)
|
f.write(content)
|
||||||
break
|
break
|
||||||
|
print(head['filename'], "接收成功")
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
sk.close()
|
sk.close()
|
||||||
@@ -810,15 +887,14 @@ sk = socket.socket()
|
|||||||
sk.connect(('127.0.0.1',8090))
|
sk.connect(('127.0.0.1',8090))
|
||||||
buffer = 1024 #读取文件的时候,每次读取的大小
|
buffer = 1024 #读取文件的时候,每次读取的大小
|
||||||
head = {
|
head = {
|
||||||
'filepath':r'C:\Users\Aaron\Desktop\新建文件夹', #需要下载的文件路径,也就是文件所在的文件夹
|
'filepath':r'C:\Users\simid\Desktop', #需要下载的文件路径,也就是文件所在的文件夹
|
||||||
'filename':'config', #改成上面filepath下的一个文件
|
'filename':'KKRIEGER.EXE', #改成上面filepath下的一个文件
|
||||||
'filesize':None,
|
'filesize':None,
|
||||||
}
|
}
|
||||||
|
|
||||||
file_path = os.path.join(head['filepath'],head['filename'])
|
file_path = os.path.join(head['filepath'],head['filename'])
|
||||||
filesize = os.path.getsize(file_path)
|
filesize = os.path.getsize(file_path)
|
||||||
head['filesize'] = filesize
|
head['filesize'] = filesize
|
||||||
# json_head = json.dumps(head,ensure_ascii=False) #字典转换成字符串
|
|
||||||
json_head = json.dumps(head) #字典转换成字符串
|
json_head = json.dumps(head) #字典转换成字符串
|
||||||
bytes_head = json_head.encode('utf-8') #字符串转换成bytes类型
|
bytes_head = json_head.encode('utf-8') #字符串转换成bytes类型
|
||||||
print(json_head)
|
print(json_head)
|
||||||
|
@@ -8,6 +8,8 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
程序员将对应于程序和数据的已穿孔的纸带(或卡片)装入输入机,然后启动输入机把程序和数据输入计算机内存,接着通过控制台开关启动程序针对数据运行;计算完毕,打印机输出计算结果;用户取走结果并卸下纸带(或卡片)后,才让下一个用户上机。
|
程序员将对应于程序和数据的已穿孔的纸带(或卡片)装入输入机,然后启动输入机把程序和数据输入计算机内存,接着通过控制台开关启动程序针对数据运行;计算完毕,打印机输出计算结果;用户取走结果并卸下纸带(或卡片)后,才让下一个用户上机。
|
||||||
|
|
||||||
手工操作方式两个特点:
|
手工操作方式两个特点:
|
||||||
@@ -87,8 +89,12 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
分时技术:把处理机的运行时间分成很短的时间片,按时间片轮流把处理机分配给各联机作业使用。
|
分时技术:把处理机的运行时间分成很短的时间片,按时间片轮流把处理机分配给各联机作业使用。
|
||||||
若某个作业在分配给它的时间片内不能完成其计算,则该作业暂时中断,把处理机让给另一作业使用,等待下一轮时再继续其运行。由于计算机速度很快,作业运行轮转得很快,给每个用户的印象是,好象他独占了一台计算机。而每个用户可以通过自己的终端向系统发出各种操作控制命令,在充分的人机交互情况下,完成作业的运行。
|
若某个作业在分配给它的时间片内不能完成其计算,则该作业暂时中断,把处理机让给另一作业使用,等待下一轮时再继续其运行。由于计算机速度很快,作业运行轮转得很快,给每个用户的印象是,好象他独占了一台计算机。而每个用户可以通过自己的终端向系统发出各种操作控制命令,在充分的人机交互情况下,完成作业的运行。
|
||||||
具有上述特征的计算机系统称为分时系统,它允许多个用户同时联机使用计算机。
|
具有上述特征的计算机系统称为分时系统,它允许多个用户同时联机使用计算机。
|
||||||
|
@@ -71,7 +71,7 @@
|
|||||||
|
|
||||||
### 状态介绍
|
### 状态介绍
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
在了解其他概念之前,我们首先要了解进程的几个状态。在程序运行的过程中,由于被操作系统的调度算法控制,程序会进入几个状态:就绪,运行和阻塞。
|
在了解其他概念之前,我们首先要了解进程的几个状态。在程序运行的过程中,由于被操作系统的调度算法控制,程序会进入几个状态:就绪,运行和阻塞。
|
||||||
|
|
||||||
@@ -172,8 +172,9 @@ process模块是一个创建进程的模块,借助这个模块,就可以完
|
|||||||
|
|
||||||
方法介绍
|
方法介绍
|
||||||
|
|
||||||
| p.start() | 启动进程,并调用该子进程中的p.run() |
|
| 方法 | 描述 |
|
||||||
| ----------------- | ------------------------------------------------------------ |
|
| ----------------- | ------------------------------------------------------------ |
|
||||||
|
| p.start() | 启动进程,并调用该子进程中的p.run() |
|
||||||
| p.run() | 进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法 |
|
| p.run() | 进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法 |
|
||||||
| p.terminate() | 强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁 |
|
| p.terminate() | 强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁 |
|
||||||
| p.is_alive() | 如果p仍然运行,返回True |
|
| 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.name | 进程的名称 |
|
||||||
| p.pid | 进程的pid |
|
| p.pid | 进程的pid |
|
||||||
| p.exitcode | 进程在运行时为None、如果为–N,表示被信号N结束(了解即可) |
|
| p.exitcode | 进程在运行时为None、如果为–N,表示被信号N结束(了解即可) |
|
||||||
@@ -209,7 +211,7 @@ if __name__ == '__main__':
|
|||||||
print('主程序')
|
print('主程序')
|
||||||
```
|
```
|
||||||
|
|
||||||
使用join方法
|
使用join方法,此方法会等待子进程结束
|
||||||
|
|
||||||
```python
|
```python
|
||||||
import time
|
import time
|
||||||
@@ -318,9 +320,9 @@ class MyProcess(Process):
|
|||||||
print('%s 正在和女主播聊天' %self.name)
|
print('%s 正在和女主播聊天' %self.name)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
p1 = MyProcess('陈松')
|
p1 = MyProcess('张三')
|
||||||
p2 = MyProcess('松哥')
|
p2 = MyProcess('李四')
|
||||||
p3 = MyProcess('松松')
|
p3 = MyProcess('王五')
|
||||||
|
|
||||||
p1.start()
|
p1.start()
|
||||||
p2.start()
|
p2.start()
|
||||||
@@ -375,7 +377,7 @@ class Myprocess(Process):
|
|||||||
print('%s正在和女主播聊天' %self.person)
|
print('%s正在和女主播聊天' %self.person)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
p=Myprocess('陈松')
|
p=Myprocess('张三')
|
||||||
p.daemon=True #一定要在p.start()前设置,设置p为守护进程,禁止p创建子进程,并且父进程代码执行结束,p即终止运行
|
p.daemon=True #一定要在p.start()前设置,设置p为守护进程,禁止p创建子进程,并且父进程代码执行结束,p即终止运行
|
||||||
p.start()
|
p.start()
|
||||||
time.sleep(10) # 在sleep时查看进程id对应的进程
|
time.sleep(10) # 在sleep时查看进程id对应的进程
|
||||||
@@ -467,12 +469,12 @@ class Myprocess(Process):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
print('%s正在和陈松聊天' %self.name)
|
print('%s正在和张三聊天' %self.name)
|
||||||
time.sleep(random.randrange(1,5))
|
time.sleep(random.randrange(1,5))
|
||||||
print('%s还在和陈松聊天' %self.name)
|
print('%s还在和张三聊天' %self.name)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
p1=Myprocess('陈松')
|
p1=Myprocess('李四')
|
||||||
p1.start()
|
p1.start()
|
||||||
|
|
||||||
p1.terminate() # 关闭进程,不会立即关闭,所以is_alive立刻查看的结果可能还是存活
|
p1.terminate() # 关闭进程,不会立即关闭,所以is_alive立刻查看的结果可能还是存活
|
||||||
@@ -501,7 +503,7 @@ class Myprocess(Process):
|
|||||||
# print('%s正在和网红脸聊天' %self.person)
|
# print('%s正在和网红脸聊天' %self.person)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
p1=Myprocess('陈松')
|
p1=Myprocess('张三')
|
||||||
p1.start()
|
p1.start()
|
||||||
print(p1.pid) #可以查看子进程的进程id
|
print(p1.pid) #可以查看子进程的进程id
|
||||||
```
|
```
|
||||||
@@ -581,7 +583,7 @@ if __name__ == '__main__':
|
|||||||
p.start()
|
p.start()
|
||||||
```
|
```
|
||||||
|
|
||||||
用说来保护票
|
用锁来保护票
|
||||||
|
|
||||||
```python
|
```python
|
||||||
#文件db的内容为:{"count":1}
|
#文件db的内容为:{"count":1}
|
||||||
|
BIN
03.网络编程与并发/03.多进程/image-20250918143648878.png
Normal file
BIN
03.网络编程与并发/03.多进程/image-20250918143648878.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 136 KiB |
BIN
03.网络编程与并发/03.多进程/image-20250918143803006.png
Normal file
BIN
03.网络编程与并发/03.多进程/image-20250918143803006.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 133 KiB |
@@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
### 使用线程的实际场景
|
### 使用线程的实际场景
|
||||||
|
|
||||||
开启一个字处理软件进程,该进程肯定需要办不止一件事情,比如监听键盘输入,处理文字,定时自动将文字保存到硬盘,这三个任务操作的都是同一块数据,因而不能用多进程。只能在一个进程里并发地开启三个线程,如果是单线程,那就只能是,键盘输入时,不能处理文字和自动保存,自动保存时又不能输入和处理文字。
|
开启一个软件进程,该进程肯定需要办不止一件事情,比如监听键盘输入,处理文字,定时自动将文字保存到硬盘,这三个任务操作的都是同一块数据,因而不能用多进程。只能在一个进程里并发地开启三个线程,如果是单线程,那就只能是,键盘输入时,不能处理文字和自动保存,自动保存时又不能输入和处理文字。
|
||||||
|
|
||||||
### 内存中的线程
|
### 内存中的线程
|
||||||
|
|
||||||
@@ -50,9 +50,9 @@
|
|||||||
### 全局解释器锁GIL
|
### 全局解释器锁GIL
|
||||||
|
|
||||||
Python代码的执行由Python虚拟机(也叫解释器主循环)来控制。Python在设计之初就考虑到要在主循环中,同时只有一个线程在执行。虽然 Python 解释器中可以“运行”多个线程,但在任意时刻只有一个线程在解释器中运行。
|
Python代码的执行由Python虚拟机(也叫解释器主循环)来控制。Python在设计之初就考虑到要在主循环中,同时只有一个线程在执行。虽然 Python 解释器中可以“运行”多个线程,但在任意时刻只有一个线程在解释器中运行。
|
||||||
对Python虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个线程在运行。
|
对Python虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个线程在运行。
|
||||||
|
|
||||||
在多线程环境中,Python 虚拟机按以下方式执行:
|
在多线程环境中,Python 虚拟机按以下方式执行:
|
||||||
|
|
||||||
1. 设置 GIL;
|
1. 设置 GIL;
|
||||||
|
|
||||||
@@ -65,7 +65,8 @@ Python代码的执行由Python虚拟机(也叫解释器主循环)来控制。Pyt
|
|||||||
5. 解锁 GIL;
|
5. 解锁 GIL;
|
||||||
|
|
||||||
6. 再次重复以上所有步骤。
|
6. 再次重复以上所有步骤。
|
||||||
在调用外部代码(如 C/C++扩展函数)的时候,GIL将会被锁定,直到这个函数结束为止(由于在这期间没有Python的字节码被运行,所以不会做线程切换)编写扩展的程序员可以主动解锁GIL。
|
|
||||||
|
在调用外部代码(如 C/C++扩展函数)的时候,GIL将会被锁定,直到这个函数结束为止(由于在这期间没有Python的字节码被运行,所以不会做线程切换)编写扩展的程序可以主动解锁GIL。
|
||||||
|
|
||||||
### python线程模块的选择
|
### python线程模块的选择
|
||||||
|
|
||||||
@@ -87,7 +88,7 @@ def sayhi(name):
|
|||||||
print('%s say hello' %name)
|
print('%s say hello' %name)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
t=Thread(target=sayhi,args=('aaron',))
|
t=Thread(target=sayhi,args=('张三',))
|
||||||
t.start()
|
t.start()
|
||||||
print('主线程')
|
print('主线程')
|
||||||
```
|
```
|
||||||
@@ -107,7 +108,7 @@ class Sayhi(Thread):
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
t = Sayhi('aaron')
|
t = Sayhi('张三')
|
||||||
t.start()
|
t.start()
|
||||||
print('主线程')
|
print('主线程')
|
||||||
```
|
```
|
||||||
@@ -256,7 +257,7 @@ import os
|
|||||||
def work():
|
def work():
|
||||||
import time
|
import time
|
||||||
time.sleep(3)
|
time.sleep(3)
|
||||||
print(threading.current_thread().getName())
|
print(threading.current_thread().name)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
@@ -264,7 +265,7 @@ if __name__ == '__main__':
|
|||||||
t=Thread(target=work)
|
t=Thread(target=work)
|
||||||
t.start()
|
t.start()
|
||||||
|
|
||||||
print(threading.current_thread().getName())
|
print(threading.current_thread().name)
|
||||||
print(threading.current_thread()) #主线程
|
print(threading.current_thread()) #主线程
|
||||||
print(threading.enumerate()) #连同主线程在内有两个运行的线程
|
print(threading.enumerate()) #连同主线程在内有两个运行的线程
|
||||||
print(threading.active_count())
|
print(threading.active_count())
|
||||||
@@ -281,7 +282,7 @@ def sayhi(name):
|
|||||||
print('%s say hello' %name)
|
print('%s say hello' %name)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
t=Thread(target=sayhi,args=('aaron',))
|
t=Thread(target=sayhi,args=('张三',))
|
||||||
t.start()
|
t.start()
|
||||||
t.join()
|
t.join()
|
||||||
print('主线程')
|
print('主线程')
|
||||||
@@ -305,8 +306,8 @@ def sayhi(name):
|
|||||||
print('%s say hello' %name)
|
print('%s say hello' %name)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
t=Thread(target=sayhi,args=('aaron',))
|
t=Thread(target=sayhi,args=('张三',))
|
||||||
t.setDaemon(True) #必须在t.start()之前设置
|
t.daemon = True #必须在t.start()之前设置
|
||||||
t.start()
|
t.start()
|
||||||
|
|
||||||
print('主线程')
|
print('主线程')
|
||||||
@@ -433,8 +434,7 @@ from threading import current_thread,Thread,Lock
|
|||||||
import os,time
|
import os,time
|
||||||
def task():
|
def task():
|
||||||
#未加锁的代码并发运行
|
#未加锁的代码并发运行
|
||||||
time.sleep(3)
|
print('%s start to run' %current_thread().name)
|
||||||
print('%s start to run' %current_thread().getName())
|
|
||||||
global n
|
global n
|
||||||
#加锁的代码串行运行
|
#加锁的代码串行运行
|
||||||
lock.acquire()
|
lock.acquire()
|
||||||
@@ -459,34 +459,10 @@ if __name__ == '__main__':
|
|||||||
```
|
```
|
||||||
|
|
||||||
有的同学可能有疑问:既然加锁会让运行变成串行,那么我在start之后立即使用join,就不用加锁了啊,也是串行的效果啊
|
有的同学可能有疑问:既然加锁会让运行变成串行,那么我在start之后立即使用join,就不用加锁了啊,也是串行的效果啊
|
||||||
没错:在start之后立刻使用jion,肯定会将100个任务的执行变成串行,毫无疑问,最终n的结果也肯定是0,是安全的,但问题是
|
没错:在start之后立刻使用join,肯定会将100个任务的执行变成串行,毫无疑问,最终n的结果也肯定是0,是安全的,但问题是
|
||||||
start后立即join:任务内的所有代码都是串行执行的,而加锁,只是加锁的部分即修改共享数据的部分是串行的
|
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))
|
|
||||||
```
|
|
||||||
|
|
||||||
### 死锁与递归锁
|
### 死锁与递归锁
|
||||||
|
|
||||||
两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为**死锁进程**
|
两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为**死锁进程**
|
||||||
|
@@ -127,7 +127,7 @@ from greenlet import greenlet
|
|||||||
|
|
||||||
def eat(name):
|
def eat(name):
|
||||||
print('%s eat 1' %name)
|
print('%s eat 1' %name)
|
||||||
g2.switch('aaron')
|
g2.switch('张三')
|
||||||
print('%s eat 2' %name)
|
print('%s eat 2' %name)
|
||||||
g2.switch()
|
g2.switch()
|
||||||
def play(name):
|
def play(name):
|
||||||
@@ -138,7 +138,7 @@ def play(name):
|
|||||||
g1=greenlet(eat)
|
g1=greenlet(eat)
|
||||||
g2=greenlet(play)
|
g2=greenlet(play)
|
||||||
|
|
||||||
g1.switch('aaron') # 可以在第一次switch时传入参数,以后都不需要
|
g1.switch('张三') # 可以在第一次switch时传入参数,以后都不需要
|
||||||
```
|
```
|
||||||
|
|
||||||
单纯的切换(在没有io的情况下或者没有重复开辟内存空间的操作),反而会降低程序的执行速度
|
单纯的切换(在没有io的情况下或者没有重复开辟内存空间的操作),反而会降低程序的执行速度
|
||||||
@@ -224,8 +224,8 @@ def play(name):
|
|||||||
print('%s play 2' %name)
|
print('%s play 2' %name)
|
||||||
|
|
||||||
|
|
||||||
g1=gevent.spawn(eat,'aaron')
|
g1=gevent.spawn(eat,'张三')
|
||||||
g2=gevent.spawn(play,name='aaron')
|
g2=gevent.spawn(play,name='张三')
|
||||||
g1.join()
|
g1.join()
|
||||||
g2.join()
|
g2.join()
|
||||||
#或者gevent.joinall([g1,g2])
|
#或者gevent.joinall([g1,g2])
|
||||||
@@ -259,7 +259,7 @@ gevent.joinall([g1,g2])
|
|||||||
print('主')
|
print('主')
|
||||||
```
|
```
|
||||||
|
|
||||||
用threading.current_thread().getName()来查看每个g1和g2,查看的结果为DummyThread-n,即假线程
|
用threading.current_thread().name来查看每个g1和g2,查看的结果为DummyThread-n,即假线程
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from gevent import monkey;monkey.patch_all()
|
from gevent import monkey;monkey.patch_all()
|
||||||
@@ -267,13 +267,13 @@ import threading
|
|||||||
import gevent
|
import gevent
|
||||||
import time
|
import time
|
||||||
def eat():
|
def eat():
|
||||||
print(threading.current_thread().getName())
|
print(threading.current_thread().name)
|
||||||
print('eat food 1')
|
print('eat food 1')
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
print('eat food 2')
|
print('eat food 2')
|
||||||
|
|
||||||
def play():
|
def play():
|
||||||
print(threading.current_thread().getName())
|
print(threading.current_thread().name)
|
||||||
print('play 1')
|
print('play 1')
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
print('play 2')
|
print('play 2')
|
||||||
@@ -372,6 +372,8 @@ def talk(conn,addr):
|
|||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
res=conn.recv(1024)
|
res=conn.recv(1024)
|
||||||
|
if len(res) == 0:
|
||||||
|
continue
|
||||||
print('client %s:%s msg: %s' %(addr[0],addr[1],res))
|
print('client %s:%s msg: %s' %(addr[0],addr[1],res))
|
||||||
conn.send(res.upper())
|
conn.send(res.upper())
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -389,7 +391,7 @@ if __name__ == '__main__':
|
|||||||
from socket import *
|
from socket import *
|
||||||
|
|
||||||
client=socket(AF_INET,SOCK_STREAM)
|
client=socket(AF_INET,SOCK_STREAM)
|
||||||
client.connect(('127.0.0.1',8080))
|
client.connect(('127.0.0.1',8088))
|
||||||
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
@@ -414,7 +416,7 @@ def client(server_ip,port):
|
|||||||
|
|
||||||
count=0
|
count=0
|
||||||
while True:
|
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)
|
msg=c.recv(1024)
|
||||||
print(msg.decode('utf-8'))
|
print(msg.decode('utf-8'))
|
||||||
count+=1
|
count+=1
|
||||||
|
Reference in New Issue
Block a user