1. Three routes and their respective comparisons
2. All letters in the configuration file must be capitalized
3. The role of if __name__
4. Several solutions to core object circular references – difficult
5. Classic errors of Flask
6. Context manager
7 .flask's multithreading and thread isolation
three routes
Method 1: decorator python C#, java can use this method
from flask import Flask
app = Flask(__name__)
@app.route('/hello')
def hello():
return 'Hello world!'
app.run(debug=True)
Method 2: Register routing php python
from flask import Flask
app = Flask(__name__)
//@app.route('/hello')
def hello():
return 'Hello world!'
app.add_url_rule('/hello', view_func=hello)
app.run(debug=True)
Method 3: python-specific rules
from flask.views import View, MethodView
from flask import Flask, render_template, request
app = Flask(__name__)
class MyView(MethodView):
def get(self):
return render_template('index.html')
def post(self):
username = request.form.get('username')
password = request.form.get('password')
if username == "gp" and password == "mypassword":
return '密码正确'
else:
return '密码错误'
app.add_url_rule('/', endpoint='login', view_func=MyView.as_view('login'))
if __name__ == '__main__':
app.run(host="0.0.0.0", port=5000)
Its process is through View's as_view -> dispatch_request in MethodView -> specific get, post and other methods.
Take a look at how flask is implemented
class View:
methods: t.Optional[t.List[str]] = None
provide_automatic_options: t.Optional[bool] = None
decorators: t.List[t.Callable] = []
def dispatch_request(self) -> ResponseReturnValue:
raise NotImplementedError()
@classmethod
def as_view(
cls, name: str, *class_args: t.Any, **class_kwargs: t.Any
) -> t.Callable:
def view(*args: t.Any, **kwargs: t.Any) -> ResponseReturnValue:
self = view.view_class(*class_args, **class_kwargs) # type: ignore
return current_app.ensure_sync(self.dispatch_request)(*args, **kwargs)
if cls.decorators:
view.__name__ = name
view.__module__ = cls.__module__
for decorator in cls.decorators:
view = decorator(view)
view.view_class = cls # type: ignore
view.__name__ = name
view.__doc__ = cls.__doc__
view.__module__ = cls.__module__
view.methods = cls.methods # type: ignore
view.provide_automatic_options = cls.provide_automatic_options # type: ignore
return view
In fact, flask returns a function through the as_view method. This function is the view function we need to bind to realize the change process from class to function.
By binding cls to the view_class attribute of the view function, implement view.view_class(*class_args, **class_kwargs)
To achieve the purpose of passing parameters, this is the charm of python. It is the closure or decorator used. And the first method type, but one is explicit and the other is implicit.
All letters in the configuration file must be capitalized
The parameters of the development environment, the test environment, and the production environment are different, so how to distinguish these three environments, if else get different environments? No, the three environments should be similar, and the configuration files should be used to separate them, and then set git ignore, each with its own configuration file.
Set config.py under the project root path
DEBUG=True
start-up file
app = Flask(__name__)
# 加载配置项
app.config.from_object("config")
# 读取
app.config["DEBUG"]
Note that flask stipulates that only all capital letters can be used, otherwise key error
The role of if __name__
It is an entry file, adding this judgment can ensure that the code in the entry file is only executed in the entry file.
if __name__ == '__main__':
app.run(host="0.0.0.0", port=5000)
Manual start is easy to understand, because he made the entry.
But the production environment is nginx+uwsgi, which is a module loaded by uwsgi. The entry file becomes uwsgi. If there is no if __name__ judgment at this time, the web server will be started twice. One is for uwsgi, the other is for the python entry file under development, and the built-in server of flask.
Is there any difference between the return of a view function and the return of a normal function?
Yes, it is not a return of a simple ordinary function, but a response object that returns a response.
The view function will not only return a string similar to helloworld,
but return a text containing status code 200, 404, 301, content-type http headers, default text/html
and return.
it is equal to
@app.route('/hello')
def hello():
return 'helloworld'
@app.route('/hello')
def hello():
return '<html></html>'
@app.route('/hello')
def hello():
headers = {
'content-type':'text/plain'
}
response = make_response('<html></html>',200)
response.headers=headers
return response
The last one will parse out html because he treats it as text/plain ordinary text, not html text.
@app.route('/hello')
def hello():
return '<html></html>', 301,headers
It is equivalent to this, flask still returns the response object.
Solve repeated references to core objects
In flask, it is a very bad experience to write the core object of the app and the registration route in the same file
from flask import Flask
app = Flask(__name__)
@app.route('/hello')
def hello():
return 'Hello world!'
app.run(debug=True)
There is no problem with only 1 or 2 routes. However, when there are hundreds of routes and 10 developers are developing at the same time, everyone modifies this entry file, which will cause a poor experience.
So we need to be able to split the route, so how can we split it?
You can manually register in the way of add_url, but this is not elegant.
I think there are two better
ways 1: keep only one core object app, define a function in util_help.py,
from flask import Flask
def my_function():
# 定义静态变量
if not hasattr(my_function, "my_static_variable"):
my_function.my_static_variable = Flask(__name__)
return my_function.my_static_variable
Anyone who uses the app object can go here to get it, because it defines a static variable, so it is unique and will not be built multiple times with package references. Registering routes is no problem.
Method 2: Normally, there will be a circular reference, because the entry file will import the app.web.book file, and the book file will go to the entry file to import the app, resulting in two apps. The app object in the book file registers the routing function , but not the app object of the entry file. At this time, the blueprint works.
Flask classic error
Working outside application context
AppContext, RequestContext, the direct relationship between Flask and Request.
The application context object Flask
request context object Request
Flask AppContext
Request RequestContext
is the source code for context management!
Use these two sentences to push current_app into the
logical use case of context management:
database:
1. Connect to the database
2. Execute sql
3. Release resources
Solution 1:
try
...
except
...
finall
...
Solution 2:
with statement, you can compare whith open() as f:
...
File reading and writing:
try:
f = open(r"D:/t.txt")
print(f.read())
finally:
f.close()
with open(r"D:/t.txt") as f:
print(f.read())
As long as the __enter__ and __exit__ methods are implemented, it is a context manager.
class A:
def __enter__(self):
a = 1
def __exit__(self,exc_type, exc_value, tb):
if tb:
print("process exception")
else:
print('no exception')
b = 2
return True
# 或者返回 False, 代表异常还需要接着抛出去,
# True 异常里面出来,外面不抛出异常
# 什么都不返回 和False 的逻辑一致
with A() as obj_A:
pass
The current obj_A is None
as what is returned is not the context manager, but the value returned by the enter method.
The variable value wrapped by the with statement has value, and after running exit, it has no value. Because push and pop are executed respectively,
push is to put the variable in, and pop will pop up.
Flask's multithreading and thread isolation
Resources are scarce, and computer resources compete for computer resources.
A process consists of at least one process, and a process is the basic unit of competing computers.
Single-core cpu, can only execute one application forever?
switch between different applications
Process scheduling Switching to another process Operating system principle
Process/thread overhead is very large Context
thread is part of a process 1 thread Multiple threads
cpu Granularity is too large Smaller unit cpu resource
thread
The process allocates resources, memory resources,
and threads use the cpu to execute code
The code instructs the cpu to execute raw materials.
Threads cannot own resources, but threads belong to processes and can access process resources.
main thread
def worker():
print("i am thread")
t = threading.current_thread()
print(t.get.getName())
import threading
print("i am 7 月")
t = threading.current_thread()
print(t.getName())
new_t = threading.Thread(target=work)
Thread names can be changed.
Multi-threading is to make full use of the performance advantages of the cpu.
Asynchronously becomes
a single-core cpu
4 core A core B core parallel execution order
Python cannot make full use of the advantages of multi-core cpu, this sentence is correct. Because python has GIL global interpreter lock global interpreter lock
Is python's multithreading tasteless? no. IO intensive is useful.
The lock is responsible for
the fine-grained lock of thread safety. The interpreter GIL multi-core CPU executes with 1 thread, which guarantees thread safety
a+=1
bytecode to a certain extent.
Is python multithreading tasteless?
Python has GIL, which is a single thread based on bytecode bytecode.
Node,js is single-process and single-threaded.
For CPU-intensive programs, multithreading is garbage, and for
IO-intensive programs, query databases, request network resources, and read and write files. Then python's multithreading makes sense.
The relationship between the flask web framework and client requests
Framework code/webserver/code written by oneself should be distinguished from
Java PHP nginx Apache Tomcat IIS
app.run is to start a flask built-in webserver
in the real environment, do not use the built-in flask, because it is single-process and single-threaded by default form of service. It is possible in the development stage, which is convenient for debugging, and it is not used when it is actually deployed. In fact, the server that comes with flask can also open its own multi-threaded model, which can open single-threaded multi-process, or multi-process, multi-threaded model.
app.run(host='0.0.0.0', debug=True, port=81,threaded=True,)
The default value of process is 1, and multiple processes can also be enabled, which is also a parameter.
For an interface, the actual request is different, how to ensure that the returned results are isolated.
For example, user a visits the bibliography list whose author is Jin Yong page=1. . User b is another one.
So, how is the instantiated request request information isolated?
It is queued under single thread, no problem. But how to do it under multithreading?
Answer: Thread isolation technology
A variable name points to multiple instantiated Requests, how to solve this problem.
import threading
request = None
request1 = Request()
request2 = Request()
request3 = Request()
## python 字典 php 数组
request = {
key1:v1
k2:v2
k3:v3
}
所以用线程的标识 作为key,文件就解决了。
request = {
thread_key1:v1
thread_key2:v2
thread_key3:v3
}
Use the basic data structure of dictionary to complete thread isolation.
Flask is accomplished with the help of the Local object of the local module under werkzeug.
The essence of the local object is to use a dictionary to solve it.
Follow the source code:
Get the id number of the current thread
Local object
How to get the value of the thread in the current thread through the thread id number?
L Thread-isolated objects
t1 La and t2 La are completely isolated and do not interfere with each other.
This Local object does not have to be used under flask, but can also be used by itself.
class A:
b = 1
my_obj = Local()
def worker():
#新线程
my_obj.b = 2
new_t = threading.Thread(target=work)
new_t.start()
time.sleep(1)
from werkzeug.local import Local
my_obj = Local()
my_obj.b = 1
def worker():
#新线程
my_obj.b = 2
print("in new thread b is :"+ str(my_obj.b))
new_t = threading.Thread(target=work)
new_t.start()
time.sleep(1)
print("in main thread b is :"+ str(my_obj.b))
Relationship between Local, LocalStack and Dictionary
The core methods push/pop and top of LocalStack, the core attribute local inherited from localStack is the object of Local().
Local uses a dictionary to achieve on-site isolation, and localstack is a thread-isolated stack structure.
Basic usage of LocalStack
The following explanation reflects the usage of LocalStack as a feature of stack.
from werkzeug.local import LocalStack
# 重点是要实现push, pop和top
s = LocalStack()
s.push(1)
s.top # 读取栈顶元素,但不会删除, 需要注意点是,以属性的形式读取的,不需要加括号
s.pop() # 获取并且弹出栈顶
And the stack is last in first out.
The following explanation reflects the usage of LocalStack as a feature of Local.
from werkzeug.local import LocalStack
my_stack = LocalStack()
my_Stack.push(1)
print("in main thread after push, value is:"+ str(my_stack.pop))
def worker():
# 新线程
print("in main thread after push, value is:"+ str(my_stack.pop))
my_Stack.push(2)
print("in main thread after push, value is:"+ str(my_stack.pop))
new_t = threading.Thread(target=work)
new_t.start()
time.sleep(1)
print("in main thread b is :"+ str(my_Stack.top))
Print the result:
It’s good to know this feature of localstack before. At that time, it was so hard to write multiple processes by hand~~~~ Solve the problem of insufficient graphics card.
Why does flask need to use localstack?
1. A stack structure is required, and the two contexts of AppContext and RequestContext are pushed into the corresponding stack structure.
2. This stack structure also needs to be thread-isolated.
It is to isolate which objects to write: 1.app, 2.Request
The essential reason is that a variable name points to the instantiation request of different threads, which is impossible. Therefore, thread isolation is required. Variables will not be polluted each other. There are three
thread-isolated objects!!!
app = create_app() and current_app have No thread isolation???
No need, because it will only be generated once in the main thread, and then bound to localProxy.