解析スレッドとコルーチンのフラスコ
01思考:各リクエストの間の関係
各要求は、我々はシリアルで、各要求が入ってきた後ならば、確かに不合理なプロセスを開いた中で私たちは、それぞれのリクエストがスレッドを使用してくることを前提としていて、それは単に、同時性を達成することはできませんでした。
そして、スレッドのデータが互いに分離されていない、不安の問題データを修正するためのデータがあります。
我々は、各スレッドが値、および印刷スレッドスレッドの変更の値を設定する必要があることを要求したとします。
from threading import Thread,current_thread
import time
class Foo(object):
def __init__(self):
self.name = 0
locals_values = Foo()
def func(num):
locals_values.name = num
time.sleep(2) # 取出该线程的名字
print(locals_values.name, current_thread().name)
for i in range(10):
# 设置该线程的名字
t = Thread(target=func,args=(i,),name='线程%s'%i)
t.start()
もちろんそれは、すべてのスレッドが終了修飾値であり、すべての時間9 2秒後にすべてのスレッドをプリントアウト時間の2秒をブロックし、そして不安のデータの問題を生じさせました。
我々は問題を解決しなければならないので、このスレッドは、以下の二つのソリューション安全ではありません。
オプション1は:ロックされています
オプションII:使用して
threading.local
変更することにデータをコピーすることを目的とし、そのようなデータの各々互いに独立しています。私たちは純粋にだけ、データを修正する第二のアプローチは、同時要求を行うために私たちのそれぞれに適している、それぞれのリクエストオブジェクトの内容がお互いのコピーが許可されているのではなく、達成するために、同時複数の同時要求を実現したいです影響を受けません。
説明:なぜ、アイデアをロックされていませんか?以下のような、アイデアは、スレッドのデータは、他の影響を与えるだろう後にデータの共有を実現するために複数のスレッドをロックし、スレッドを変更するためにグラブ票に12306に類似したシナリオに適している、と私たちは何をする必要がある要求並行オブジェクトであります変更が要求オブジェクトのこの部分に任意のスレッド他のスレッドに影響しないことを実現しています。だから、オプションIIを使用
02 threading.local
各スレッドのデータ記憶のためのスペースを開くために使用される各スレッドに同一のデータ、データの複数のコピーを変更する複数のスレッド
例:
from threading import Thread,current_thread,local
import time
locals_values = local()
# 可以简单理解为,识别到新的线程的时候,都会开辟一片新的内存空间,相当于每个线程对该值进行了拷贝。
def func(num):
locals_values.name = num
time.sleep(2)
print(locals_values.name, current_thread().name)
for i in range(10):
t = Thread(target=func,args=(i,),name='线程%s'%i)
t.start()
達成するために、オブジェクトをインスタンス化することによってthreading.localとしてマルチスレッドの各スレッドに、データのコピーが同じデータを変更し、また、自分自身のデータを変更しています。私たちが望む効果を達成するために。
threading.localによる03のカスタム辞書
例:
from threading import get_ident,Thread,current_thread
# get_ident()可以获取每个线程的唯一标记,
import time
class Local(object):
storage = {}# 初始化一个字典
get_ident = get_ident # 拿到get_ident的地址
def set(self,k,v):
ident =self.get_ident()# 获取当前线程的唯一标记
origin = self.storage.get(ident)
if not origin:
origin={}
origin[k] = v
self.storage[ident] = origin
def get(self,k):
ident = self.get_ident() # 获取当前线程的唯一标记
v= self.storage[ident].get(k)
return v
locals_values = Local()
def func(num):
# get_ident() 获取当前线程的唯一标记
locals_values.set('KEY',num)
time.sleep(2)
print(locals_values.get('KEY'),current_thread().name)
for i in range(10):
t = Thread(target=func,args=(i,),name='线程%s'%i)
t.start()
説明:
使用して、get_ident()
キーとしてスレッドごとに一意のタグを取得し、その後、辞書ストレージを整理します。
等:{独特のマーキングスレッド1:{K:V}、ユニークなマーキングスレッド2:{K:V}} .......
{
15088: {'KEY': 0},
8856: {'KEY': 1},
17052: {'KEY': 2},
8836: {'KEY': 3},
13832: {'KEY': 4},
15504: {'KEY': 5},
16588: {'KEY': 6},
5164: {'KEY': 7},
560: {'KEY': 8},
1812: {'KEY': 9}
}
業績:
SETATTRとGETATTRしてカスタムthrethreading.localを実装する04
例:
from threading import get_ident,Thread,current_thread
# get_ident()可以获取每个线程的唯一标记,
import time
class Local(object):
storage = {}# 初始化一个字典
get_ident = get_ident # 拿到get_ident的地址
def __setattr__(self, k, v):
ident =self.get_ident()# 获取当前线程的唯一标记
origin = self.storage.get(ident)
if not origin:
origin={}
origin[k] = v
self.storage[ident] = origin
def __getattr__(self, k):
ident = self.get_ident() # 获取当前线程的唯一标记
v= self.storage[ident].get(k)
return v
locals_values = Local()
def func(num):
# get_ident() 获取当前线程的唯一标记
locals_values.KEY=num
time.sleep(2)
print(locals_values.KEY,current_thread().name)
for i in range(10):
t = Thread(target=func,args=(i,),name='线程%s'%i)
t.start()
05各オブジェクトは、独自のメモリ空間(辞書)を持っています
私たちは、threading.local機能を実現し、今問題があり、我々はより多くのローカルオブジェクトを生成したいのですが、マネージスレッドで複数のオブジェクトの内容を引き起こす可能性があればローカル設定は、クラス属性記憶に配置されている= {}カスタマイズすることができます内部に、私たちは地元のオブジェクトがそれらに対応するストレージの内部に配置されている各スレッドセットの内容を実現したい場合、我々は、コードを再設計する必要があります。
例:
from threading import get_ident,Thread,current_thread
# get_ident()可以获取每个线程的唯一标记,
import time
class Local(object):
def __init__(self):
# 千万不要按照注释里这么写,否则会造成递归死循环,死循环在__getattr__中,不理解的话可以全程使用debug测试。
# self.storage = {}
# self.get_ident =get_ident
object.__setattr__(self,"storage",{})
object.__setattr__(self,"get_ident",get_ident) # 借用父类设置对象的属性,避免递归死循环。
def __setattr__(self, k, v):
ident =self.get_ident() # 获取当前线程的唯一标记
origin = self.storage.get(ident)
if not origin:
origin={}
origin[k] = v
self.storage[ident] = origin
def __getattr__(self, k):
ident = self.get_ident() # 获取当前线程的唯一标记
v= self.storage[ident].get(k)
return v
locals_values = Local()
locals_values2 = Local()
def func(num):
# get_ident() 获取当前线程的唯一标记
# locals_values.set('KEY',num)
locals_values.KEY=num
time.sleep(2)
print(locals_values.KEY,current_thread().name)
# print('locals_values2.storage:',locals_values2.storage) # 查看locals_values2.storage的私有的storage
for i in range(10):
t = Thread(target=func,args=(i,),name='线程%s'%i)
t.start()
私が実証され表示されませんし、最初のいくつかの例は、同じ効果を発揮します。
06これはあなたが同時要求のフラスコを設計する方法をである場合には?
事例1:グローバル変数に基づいてシングルスレッドのプロセスは、行うことができます
ケース2:シングルプロセスマルチスレッドのでthreading.localに基づいて物体
ケース3:シングルプロセスマルチコルーチン、マルチスレッド、どのように行うには?
ヒント:コルーチンはコルーチンは、オペレーティングシステムが自動的に遭遇したスイッチに置き換えられます、アプリケーションレベルで
IO
の低レベルのタスクをまたはタスクを実行し、アプリケーションレベルの切り替えは、オペレーティングシステムの切り替えよりもはるかに高い速度もちろん、それは並列プログラムの性能を向上させるために、自分自身のフレームワークを設計することであるならば、それは3人の控訴の場合でなければならないだけでなく、マルチスレッドとマルチコルーチン、そしてどのようにそれを設計することを検討して?
基礎となるに応じて、同時実行性の要件、という順序で私たちのフラスコ中で、
werkzeug
外部のパッケージには、werkzeug
セキュリティやマルチプロセスを確実にするために、マルチスレッド達成するために、werkzeug
同じ基本設計とケースの上に、唯一の違いは、インポートを行うための時間ですステッププロセスは、私を見てみましょうwerkzeug
ソースコードを。werkzeug.local.py
ソースコードの一部... try: from greenlet import getcurrent as get_ident # 拿到携程的唯一标识 except ImportError: try: from thread import get_ident #线程的唯一标识 except ImportError: from _thread import get_ident class Local(object): ... def __init__(self): object.__setattr__(self, '__storage__', {}) object.__setattr__(self, '__ident_func__', get_ident) ... def __getattr__(self, name): try: return self.__storage__[self.__ident_func__()][name] except KeyError: raise AttributeError(name) def __setattr__(self, name, value): ident = self.__ident_func__() storage = self.__storage__ try: storage[ident][name] = value except KeyError: storage[ident] = {name: value}
分析:
原理は非常にユニークな輸入のスレッドとコルーチン統一名を識別することから始まるであり
get_ident
、エラーの説明がコルーチンをサポートしていない場合、およびときに最初のインポートコルーチンモジュールのインポートスレッドに移動しますget_ident
ので、それが唯一の共同であるかどうかを実行しているスレッドや、チェンの走行がセットに固有のIDと、このスレッドやコルーチン必要性のアイデンティティを取得することができますに分類保管され__storage__
た辞書。