ホームページ バックエンド開発 Python チュートリアル Pythonのプロセス、スレッド、コルーチンの詳細な説明

Pythonのプロセス、スレッド、コルーチンの詳細な説明

Nov 07, 2016 am 11:21 AM

プロセスとスレッドの歴史

コンピューターがハードウェアとソフトウェアで構成されていることは誰もが知っています。ハードウェアの CPU はコンピュータの中核であり、コンピュータのすべてのタスクを実行します。 オペレーティング システムはハードウェア上で実行されるソフトウェアであり、リソースの管理と割り当て、およびタスクのスケジュールを担当します。 プログラムとは、ブラウザや音楽プレーヤーなど、システム上で動作する特定の機能を備えたソフトウェアのことです。 プログラムが実行されるたびに、特定の機能が完了します。たとえば、ブラウザーが Web ページを開くには、プログラムの実行を管理および制御するための特別なデータ構造が必要です。プロセス制御ブロック。 プロセスは、データ セットに対するプログラムの動的実行です。 プロセスは通常、プログラム、データセット、プロセス制御ブロックの 3 つの部分で構成されます。作成するプログラムは、プロセスが完了する必要がある機能とその完了方法を記述するために使用されます。データセットは、プログラムが実行中に使用する必要があるリソースです。プロセス制御ブロックは、プロセスの外部特性を記録するために使用されます。 、プロセスの実行変更プロセスを記述し、プロセスの制御と管理に使用できます。これは、システムがプロセスの存在を感知する唯一の兆候です。


初期のオペレーティング システムでは、コンピューターにはプロセス実行の最小単位であるコアが 1 つしかありませんでした。タスク スケジューリングでは、プロセス スケジューリングにタイム スライス ローテーション プリエンプティブ方式が使用されていました。各プロセスには独自の独立したメモリがあり、プロセス間のメモリ アドレス空間が確実に分離されます。 コンピューター技術の発展に伴い、プロセスには多くの欠点が生じています。第 1 に、SMP とも呼ばれる対称型マルチプロセッシング (Symmetrical Multi-Processing) のせいで、プロセスの作成、キャンセル、切り替えのコストが比較的高くなります。プロセッサのグループ (複数の CPU) が 1 台のコンピュータ上に組み立てられ、共有メモリ サブシステムと CPU 間のバス構造の出現により、複数の実行ユニットを満たすことができますが、複数のプロセスの並列オーバーヘッドが大きすぎます。 このとき、スレッドの概念が導入されました。 スレッドは軽量プロセスとも呼ばれ、CPU の基本的な実行単位であり、スレッド ID、プログラム カウンタ、レジスタ セット、スタックから構成されます。スレッドの導入により、プログラムの同時実行のオーバーヘッドが削減され、オペレーティング システムの同時実行パフォーマンスが向上します。 スレッドには独自のシステム リソースはなく、実行時に必要なリソースのみがあります。ただし、スレッドは、プロセスが所有する他のリソースを、同じプロセスに属する他のスレッドと共有できます。


プロセスとスレッドの関係

スレッドはプロセス空間で実行され、プロセスが終了すると、そのプロセスによって生成されたすべてのスレッドが同じメモリ空間を共有します。強制終了して削除されました。スレッドは、プロセスが所有するすべてのリソースを同じプロセスに属する他のスレッドと共有できますが、スレッド自体は基本的にシステム リソースを所有せず、実行に不可欠な情報 (プログラム カウンター、レジスタのセットなど) を少しだけ所有します。 、およびスタック)。

Python スレッド

スレッドは、スレッド関連の操作を提供するために使用されます。スレッドは、アプリケーションの最小の作業単位です。

1. スレッディング モジュール

スレッディング モジュールは _thread モジュール上に構築されます。スレッド モジュールは、低レベルの原始的な方法でスレッドを処理および制御しますが、スレッド モジュールは、スレッドの二次カプセル化によってスレッドを処理するためのより便利な API を提供します。

import threading
import time
   
def worker(num):
    """
    thread worker function
    :return:
    """
    time.sleep(1)
    print("The num is  %d" % num)
    return
   
for i in range(20):
    t = threading.Thread(target=worker,args=(i,),name=“t.%d” % i)
    t.start()
ログイン後にコピー

上記のコードは 20 個の「フォアグラウンド」スレッドを作成し、その後コントローラーが CPU に渡され、CPU は指定されたアルゴリズムに従ってスケジュールを設定し、命令をスライスで実行します。

スレッドメソッドの説明

t.start(): スレッドをアクティブにする

t.getName(): スレッドの名前を取得する

t.setName(): スレッドの名前を設定する

t.name : スレッドを取得または設定します

t.is_alive() の名前: スレッドがアクティブかどうかを判断します

t.isAlive(): スレッドがアクティブかどうかを判断します

t.setDaemon() バックグラウンド スレッドまたはフォアグラウンド スレッドに設定しますthread (デフォルト: False); スレッドがデーモン スレッドであるかどうかをブール値で設定します。これは start() メソッドの実行後にのみ使用できます。バックグラウンド スレッドの場合は、メイン スレッドの実行中にバックグラウンド スレッドも実行されます。メイン スレッドの実行後、バックグラウンド スレッドがフォアグラウンド スレッドの場合は、成功または失敗に関係なく停止します。メインスレッドの実行中に実行されます。メインスレッドが実行を完了した後、フォアグラウンドスレッドが実行を完了するのを待ってからプログラムが停止します。

t.ident かどうかを判断します。 : スレッドの識別子を取得します。スレッド識別子はゼロ以外の整数です。このプロパティは start() メソッドが呼び出された後にのみ有効で、それ以外の場合は単に None を返します。

t.join(): 各スレッドを 1 つずつ実行し、完了後に実行を継続します。このメソッドではマルチスレッドが無意味になります。

t.run(): スレッドはスケジュールされた後にスレッド オブジェクトの実行を自動的に実行します。メソッド

2、スレッドロック threading.RLock と threading.Lock

スレッドはランダムにスケジュールされ、各スレッドは n 回しか実行できないため、CPU は他のスレッドを実行します。データの正確性を確保するために、ロックの概念が導入されています。したがって、次の問題が発生する可能性があります:

例:假设列表A的所有元素就为0,当一个线程从前向后打印列表的所有元素,另外一个线程则从后向前修改列表的元素为1,那么输出的时候,列表的元素就会一部分为0,一部分为1,这就导致了数据的不一致。锁的出现解决了这个问题。

import threading
import time
   
globals_num = 0
   
lock = threading.RLock()
   
def Func():
    lock.acquire()  # 获得锁
    global globals_num
    globals_num += 1
    time.sleep(1)
    print(globals_num)
    lock.release()  # 释放锁
   
for i in range(10):
    t = threading.Thread(target=Func)
    t.start()
ログイン後にコピー

3、threading.RLock和threading.Lock 的区别

RLock允许在同一线程中被多次acquire。而Lock却不允许这种情况。 如果使用RLock,那么acquire和release必须成对出现,即调用了n次acquire,必须调用n次的release才能真正释放所占用的琐。

import threading
lock = threading.Lock()    #Lock对象
lock.acquire()
lock.acquire()  #产生了死琐。
lock.release()
lock.release() 
import threading
rLock = threading.RLock()  #RLock对象
rLock.acquire()
rLock.acquire()    #在同一线程内,程序不会堵塞。
rLock.release()
rLock.release()
ログイン後にコピー

4、threading.Event

python线程的事件用于主线程控制其他线程的执行,事件主要提供了三个方法 set、wait、clear。

事件处理的机制:全局定义了一个“Flag”,如果“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞,如果“Flag”值为True,那么event.wait 方法时便不再阻塞。

clear:将“Flag”设置为False

set:将“Flag”设置为True

Event.isSet() :判断标识位是否为Ture。

import threading
   
def do(event):
    print('start')
    event.wait()
    print('execute')
   
event_obj = threading.Event()
for i in range(10):
    t = threading.Thread(target=do, args=(event_obj,))
    t.start()
   
event_obj.clear()
inp = input('input:')
if inp == 'true':
    event_obj.set()
ログイン後にコピー

当线程执行的时候,如果flag为False,则线程会阻塞,当flag为True的时候,线程不会阻塞。它提供了本地和远程的并发性。

5、threading.Condition

一个condition变量总是与某些类型的锁相联系,这个可以使用默认的情况或创建一个,当几个condition变量必须共享和同一个锁的时候,是很有用的。锁是conditon对象的一部分:没有必要分别跟踪。

condition变量服从上下文管理协议:with语句块封闭之前可以获取与锁的联系。 acquire() 和 release() 会调用与锁相关联的相应的方法。

其他和锁关联的方法必须被调用,wait()方法会释放锁,当另外一个线程使用 notify() or notify_all()唤醒它之前会一直阻塞。一旦被唤醒,wait()会重新获得锁并返回,

Condition类实现了一个conditon变量。 这个conditiaon变量允许一个或多个线程等待,直到他们被另一个线程通知。 如果lock参数,被给定一个非空的值,,那么他必须是一个lock或者Rlock对象,它用来做底层锁。否则,会创建一个新的Rlock对象,用来做底层锁。

wait(timeout=None) : 等待通知,或者等到设定的超时时间。当调用这wait()方法时,如果调用它的线程没有得到锁,那么会抛出一个RuntimeError 异常。 wati()释放锁以后,在被调用相同条件的另一个进程用notify() or notify_all() 叫醒之前 会一直阻塞。wait() 还可以指定一个超时时间。

如果有等待的线程,notify()方法会唤醒一个在等待conditon变量的线程。notify_all() 则会唤醒所有在等待conditon变量的线程。

注意: notify()和notify_all()不会释放锁,也就是说,线程被唤醒后不会立刻返回他们的wait() 调用。除非线程调用notify()和notify_all()之后放弃了锁的所有权。

在典型的设计风格里,利用condition变量用锁去通许访问一些共享状态,线程在获取到它想得到的状态前,会反复调用wait()。修改状态的线程在他们状态改变时调用 notify() or notify_all(),用这种方式,线程会尽可能的获取到想要的一个等待者状态。 例子: 生产者-消费者模型,

import threading
import time
def consumer(cond):
    with cond:
        print("consumer before wait")
        cond.wait()
        print("consumer after wait")
   
def producer(cond):
    with cond:
        print("producer before notifyAll")
        cond.notifyAll()
        print("producer after notifyAll")
   
condition = threading.Condition()
c1 = threading.Thread(name="c1", target=consumer, args=(condition,))
c2 = threading.Thread(name="c2", target=consumer, args=(condition,))
   
p = threading.Thread(name="p", target=producer, args=(condition,))
   
c1.start()
time.sleep(2)
c2.start()
time.sleep(2)
p.start()
ログイン後にコピー

6、queue模块

Queue 就是对队列,它是线程安全的

举例来说,我们去麦当劳吃饭。饭店里面有厨师职位,前台负责把厨房做好的饭卖给顾客,顾客则去前台领取做好的饭。这里的前台就相当于我们的队列。形成管道样,厨师做好饭通过前台传送给顾客,所谓单向队列

这个模型也叫生产者-消费者模型。

import queue
q = queue.Queue(maxsize=0)  # 构造一个先进显出队列,maxsize指定队列长度,为0 时,表示队列长度无限制。
q.join()    # 等到队列为kong的时候,在执行别的操作
q.qsize()   # 返回队列的大小 (不可靠)
q.empty()   # 当队列为空的时候,返回True 否则返回False (不可靠)
q.full()    # 当队列满的时候,返回True,否则返回False (不可靠)
q.put(item, block=True, timeout=None) #  将item放入Queue尾部,item必须存在,可以参数block默认为True,表示当队列满时,会等待队列给出可用位置,
                         为False时为非阻塞,此时如果队列已满,会引发queue.Full 异常。 可选参数timeout,表示 会阻塞设置的时间,过后,
                          如果队列无法给出放入item的位置,则引发 queue.Full 异常
q.get(block=True, timeout=None) #   移除并返回队列头部的一个值,可选参数block默认为True,表示获取值的时候,如果队列为空,则阻塞,为False时,不阻塞,
                      若此时队列为空,则引发 queue.Empty异常。 可选参数timeout,表示会阻塞设置的时候,过后,如果队列为空,则引发Empty异常。
q.put_nowait(item) #   等效于 put(item,block=False)
q.get_nowait() #    等效于 get(item,block=False)
ログイン後にコピー

代码如下:

#!/usr/bin/env python
import Queue
import threading
message = Queue.Queue(10)
  
  
def producer(i):
    while True:
        message.put(i)
  
  
def consumer(i):
    while True:
        msg = message.get()
  
  
for i in range(12):
    t = threading.Thread(target=producer, args=(i,))
    t.start()
  
for i in range(10):
    t = threading.Thread(target=consumer, args=(i,))
    t.start()
ログイン後にコピー

那就自己做个线程池吧:

# 简单往队列中传输线程数
import threading
import time
import queue
class Threadingpool():
    def __init__(self,max_num = 10):
        self.queue = queue.Queue(max_num)
        for i in range(max_num):
            self.queue.put(threading.Thread)
    def getthreading(self):
        return self.queue.get()
    def addthreading(self):
        self.queue.put(threading.Thread)
def func(p,i):
    time.sleep(1)
    print(i)
    p.addthreading()
if __name__ == "__main__":
    p = Threadingpool()
    for i in range(20):
        thread = p.getthreading()
        t = thread(target = func, args = (p,i))
        t.start()
ログイン後にコピー
#往队列中无限添加任务
import queue
import threading
import contextlib
import time
StopEvent = object()
class ThreadPool(object):
    def __init__(self, max_num):
        self.q = queue.Queue()
        self.max_num = max_num
        self.terminal = False
        self.generate_list = []
        self.free_list = []
    def run(self, func, args, callback=None):
        """
        线程池执行一个任务
        :param func: 任务函数
        :param args: 任务函数所需参数
        :param callback: 任务执行失败或成功后执行的回调函数,回调函数有两个参数1、任务函数执行状态;2、任务函数返回值(默认为None,即:不执行回调函数)
        :return: 如果线程池已经终止,则返回True否则None
        """
        if len(self.free_list) == 0 and len(self.generate_list) < self.max_num:
            self.generate_thread()
        w = (func, args, callback,)
        self.q.put(w)
    def generate_thread(self):
        """
        创建一个线程
        """
        t = threading.Thread(target=self.call)
        t.start()
    def call(self):
        """
        循环去获取任务函数并执行任务函数
        """
        current_thread = threading.currentThread
        self.generate_list.append(current_thread)
        event = self.q.get()  # 获取线程
        while event != StopEvent:   # 判断获取的线程数不等于全局变量
            func, arguments, callback = event   # 拆分元祖,获得执行函数,参数,回调函数
            try:
                result = func(*arguments)   # 执行函数
                status = True
            except Exception as e:    # 函数执行失败
                status = False
                result = e
            if callback is not None:
                try:
                    callback(status, result)
                except Exception as e:
                    pass
            # self.free_list.append(current_thread)
            # event = self.q.get()
            # self.free_list.remove(current_thread)
            with self.work_state():
                event = self.q.get()
        else:
            self.generate_list.remove(current_thread)
    def close(self):
        """
        关闭线程,给传输全局非元祖的变量来进行关闭
        :return:
        """
        for i in range(len(self.generate_list)):
            self.q.put(StopEvent)
    def terminate(self):
        """
        突然关闭线程
        :return:
        """
        self.terminal = True
        while self.generate_list:
            self.q.put(StopEvent)
        self.q.empty()
    @contextlib.contextmanager
    def work_state(self):
        self.free_list.append(threading.currentThread)
        try:
            yield
        finally:
            self.free_list.remove(threading.currentThread)
def work(i):
    print(i)
    return i +1 # 返回给回调函数
def callback(ret):
    print(ret)
pool = ThreadPool(10)
for item in range(50):
    pool.run(func=work, args=(item,),callback=callback)
pool.terminate()
# pool.close()
ログイン後にコピー

python 进程

multiprocessing是python的多进程管理包,和threading.Thread类似。

1、multiprocessing模块

直接从侧面用subprocesses替换线程使用GIL的方式,由于这一点,multiprocessing模块可以让程序员在给定的机器上充分的利用CPU。在multiprocessing中,通过创建Process对象生成进程,然后调用它的start()方法,

from multiprocessing import Process
  
def func(name):
    print(&#39;hello&#39;, name)
  
 
if __name__ == "__main__":
    p = Process(target=func,args=(&#39;zhangyanlin&#39;,))
    p.start()
    p.join()  # 等待进程执行完毕
ログイン後にコピー

在使用并发设计的时候最好尽可能的避免共享数据,尤其是在使用多进程的时候。 如果你真有需要 要共享数据, multiprocessing提供了两种方式。

(1)multiprocessing,Array,Value

数据可以用Value或Array存储在一个共享内存地图里,如下:

from multiprocessing import Array,Value,Process
  
def func(a,b):
    a.value = 3.333333333333333
    for i in range(len(b)):
        b[i] = -b[i]
  
  
if __name__ == "__main__":
    num = Value(&#39;d&#39;,0.0)
    arr = Array(&#39;i&#39;,range(11))
  
  
    c = Process(target=func,args=(num,arr))
    d= Process(target=func,args=(num,arr))
    c.start()
    d.start()
    c.join()
    d.join()
  
    print(num.value)
    for i in arr:
        print(i)
ログイン後にコピー

输出:

3.1415927

[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]

创建num和arr时,“d”和“i”参数由Array模块使用的typecodes创建:“d”表示一个双精度的浮点数,“i”表示一个有符号的整数,这些共享对象将被线程安全的处理。

Array(‘i’, range(10))中的‘i’参数:

‘c’: ctypes.c_char     ‘u’: ctypes.c_wchar    ‘b’: ctypes.c_byte     ‘B’: ctypes.c_ubyte

‘h’: ctypes.c_short    ‘H’: ctypes.c_ushort   ‘i’: ctypes.c_int      ‘I’: ctypes.c_uint

‘l’: ctypes.c_long,    ‘L’: ctypes.c_ulong    ‘f’: ctypes.c_float    ‘d’: ctypes.c_double

(2)multiprocessing,Manager

由Manager()返回的manager提供list, dict, Namespace, Lock, RLock, Semaphore, BoundedSemaphore, Condition, Event, Barrier, Queue, Value and Array类型的支持。

from multiprocessing import Process,Manager
def f(d,l):
    d["name"] = "zhangyanlin"
    d["age"] = 18
    d["Job"] = "pythoner"
    l.reverse()
  
if __name__ == "__main__":
    with Manager() as man:
        d = man.dict()
        l = man.list(range(10))
  
        p = Process(target=f,args=(d,l))
        p.start()
        p.join()
  
        print(d)
        print(l)
ログイン後にコピー

输出:

{0.25: None, 1: '1', '2': 2}

[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

Server process manager比 shared memory 更灵活,因为它可以支持任意的对象类型。另外,一个单独的manager可以通过进程在网络上不同的计算机之间共享,不过他比shared memory要慢。

2、进程池(Using a pool of workers)

Pool类描述了一个工作进程池,他有几种不同的方法让任务卸载工作进程。

进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止。

我们可以用Pool类创建一个进程池, 展开提交的任务给进程池。 例:

#apply
from  multiprocessing import Pool
import time
  
def f1(i):
    time.sleep(0.5)
    print(i)
    return i + 100
  
if __name__ == "__main__":
    pool = Pool(5)
    for i in range(1,31):
        pool.apply(func=f1,args=(i,))
  
#apply_async
def f1(i):
    time.sleep(0.5)
    print(i)
    return i + 100
def f2(arg):
    print(arg)
  
if __name__ == "__main__":
    pool = Pool(5)
    for i in range(1,31):
        pool.apply_async(func=f1,args=(i,),callback=f2)
    pool.close()
    pool.join()
ログイン後にコピー

一个进程池对象可以控制工作进程池的哪些工作可以被提交,它支持超时和回调的异步结果,有一个类似map的实现。


processes :使用的工作进程的数量,如果processes是None那么使用 os.cpu_count()返回的数量。

initializer: 如果initializer是None,那么每一个工作进程在开始的时候会调用initializer(*initargs)。

maxtasksperchild:工作进程退出之前可以完成的任务数,完成后用一个心的工作进程来替代原进程,来让闲置的资源被释放。maxtasksperchild默认是None,意味着只要Pool存在工作进程就会一直存活。

context: 用在制定工作进程启动时的上下文,一般使用 multiprocessing.Pool() 或者一个context对象的Pool()方法来创建一个池,两种方法都适当的设置了context

注意:Pool对象的方法只可以被创建pool的进程所调用。

New in version 3.2: maxtasksperchild
New in version 3.4: context
ログイン後にコピー


进程池的方法

apply(func[, args[, kwds]])
ログイン後にコピー

:使用arg和kwds参数调用func函数,结果返回前会一直阻塞,由于这个原因,apply_async()更适合并发执行,另外,func函数仅被pool中的一个进程运行。

apply_async(func[, args[, kwds[, callback[, error_callback]]]]) : apply()方法的一个变体,会返回一个结果对象。如果callback被指定,那么callback可以接收一个参数然后被调用,当结果准备好回调时会调用callback,调用失败时,则用error_callback替换callback。 Callbacks应被立即完成,否则处理结果的线程会被阻塞。

close() : 阻止更多的任务提交到pool,待任务完成后,工作进程会退出。

terminate() : 不管任务是否完成,立即停止工作进程。在对pool对象进程垃圾回收的时候,会立即调用terminate()。

join() : wait工作线程的退出,在调用join()前,必须调用close() or terminate()。这样是因为被终止的进程需要被父进程调用wait(join等价与wait),否则进程会成为僵尸进程。

map(func, iterable[, chunksize])¶
map_async(func, iterable[, chunksize[, callback[, error_callback]]])¶
imap(func, iterable[, chunksize])¶
imap_unordered(func, iterable[, chunksize])
starmap(func, iterable[, chunksize])¶
starmap_async(func, iterable[, chunksize[, callback[, error_back]]])
ログイン後にコピー

python 协程

线程和进程的操作是由程序触发系统接口,最后的执行者是系统;协程的操作则是程序员。


协程存在的意义:对于多线程应用,CPU通过切片的方式来切换线程间的执行,线程切换时需要耗时(保存状态,下次继续)。协程,则只使用一个线程,在一个线程中规定某个代码块执行顺序。


协程的适用场景:当程序中存在大量不需要CPU的操作时(IO),适用于协程;


event loop是协程执行的控制点, 如果你希望执行协程, 就需要用到它们。


event loop提供了如下的特性:

注册、执行、取消延时调用(异步函数)

创建用于通信的client和server协议(工具)

创建和别的程序通信的子进程和协议(工具)

把函数调用送入线程池中

协程示例:

import asyncio
   
async def cor1():
    print("COR1 start")
    await cor2()
    print("COR1 end")
   
async def cor2():
    print("COR2")
   
loop = asyncio.get_event_loop()
loop.run_until_complete(cor1())
loop.close()
ログイン後にコピー

最后三行是重点。

asyncio.get_event_loop() : asyncio启动默认的event loop

run_until_complete() : 这个函数是阻塞执行的,知道所有的异步函数执行完成,

close() : 关闭event loop。

1、greenlet

import greenlet
def fun1():
    print("12")
    gr2.switch()
    print("56")
    gr2.switch()
  
def fun2():
    print("34")
    gr1.switch()
    print("78")
  
  
gr1 = greenlet.greenlet(fun1)
gr2 = greenlet.greenlet(fun2)
gr1.switch()
ログイン後にコピー

2、gevent

gevent属于第三方模块需要下载安装包

pip3 install --upgrade pip3
pip3 install gevent
ログイン後にコピー
import gevent
def fun1():
    print("www.baidu.com")   # 第一步
    gevent.sleep(0)
    print("end the baidu.com")  # 第三步
  
def fun2():
    print("www.zhihu.com")   # 第二步
    gevent.sleep(0)
    print("end th zhihu.com")  # 第四步
  
gevent.joinall([
    gevent.spawn(fun1),
    gevent.spawn(fun2),
])
ログイン後にコピー

遇到IO操作自动切换:

import gevent
import requests
def func(url):
    print("get: %s"%url)
    gevent.sleep(0)
    date =requests.get(url)
    ret = date.text
    print(url,len(ret))
gevent.joinall([
    gevent.spawn(func, &#39;https://www.pythontab.com/&#39;),
    gevent.spawn(func, &#39;https://www.yahoo.com/&#39;),
    gevent.spawn(func, &#39;https://github.com/&#39;),
])
ログイン後にコピー


文章转自:http://www.cnblogs.com/aylin/p/5601969.html


このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

golang 関数と goroutine の親子関係 golang 関数と goroutine の親子関係 Apr 25, 2024 pm 12:57 PM

Go では関数とゴルーチンの間に親子関係があり、親ゴルーチンは子ゴルーチンを作成し、子ゴルーチンは親ゴルーチンの変数にアクセスできますが、その逆はできません。 go キーワードを使用して子ゴルーチンを作成すると、子ゴルーチンは匿名関数または名前付き関数を通じて実行されます。親ゴルーチンは、すべての子ゴルーチンが完了する前にプログラムが終了しないように、sync.WaitGroup を介して子ゴルーチンが完了するのを待つことができます。

Golang API 設計における同時実行性とコルーチンの適用 Golang API 設計における同時実行性とコルーチンの適用 May 07, 2024 pm 06:51 PM

同時実行性とコルーチンは、GoAPI 設計で次の目的で使用されます。 高パフォーマンス処理: 複数のリクエストを同時に処理してパフォーマンスを向上させます。非同期処理: コルーチンを使用してタスク (電子メールの送信など) を非同期に処理し、メインスレッドを解放します。ストリーム処理: コルーチンを使用して、データ ストリーム (データベース読み取りなど) を効率的に処理します。

C++ 同時プログラミング: スレッドの枯渇と優先順位の逆転を回避するには? C++ 同時プログラミング: スレッドの枯渇と優先順位の逆転を回避するには? May 06, 2024 pm 05:27 PM

スレッドの枯渇を回避するには、公平なロックを使用してリソースの公平な割り当てを確保するか、スレッドの優先順位を設定します。優先順位の逆転を解決するには、リソースを保持しているスレッドの優先順位を一時的に高める優先順位の継承を使用するか、リソースを必要とするスレッドの優先順位を高めるロック プロモーションを使用します。

Golang コルーチンのライフサイクルを制御するにはどうすればよいですか? Golang コルーチンのライフサイクルを制御するにはどうすればよいですか? May 31, 2024 pm 06:05 PM

Go コルーチンのライフ サイクルは、次の方法で制御できます。 コルーチンを作成します。 go キーワードを使用して、新しいタスクを開始します。コルーチンを終了する: すべてのコルーチンが完了するまで待ち、sync.WaitGroup を使用します。チャネル終了信号を使用します。コンテキスト context.Context を使用します。

C++ 同時プログラミング: スレッドの終了とキャンセルを行うには? C++ 同時プログラミング: スレッドの終了とキャンセルを行うには? May 06, 2024 pm 02:12 PM

C++ のスレッド終了およびキャンセル メカニズムには次のものがあります。 スレッド終了: std::thread::join() は、ターゲット スレッドが実行を完了するまで現在のスレッドをブロックします。 std::thread::detach() は、ターゲット スレッドをスレッド管理から切り離します。スレッドのキャンセル: std::thread::request_termination() はターゲット スレッドに実行の終了を要求します。 std::thread::get_id() はターゲット スレッド ID を取得し、std::terminate() とともに使用してターゲットを即座に終了できます。糸。実際の戦闘では、request_termination() によってスレッドが終了のタイミングを決定でき、join() によってメインラインでそれが保証されます。

Python asyncio の上級ガイド: 初心者から専門家まで Python asyncio の上級ガイド: 初心者から専門家まで Mar 04, 2024 am 09:43 AM

同時プログラミングと非同期プログラミング 同時プログラミングは、同時に実行される複数のタスクを扱います。非同期プログラミングは、タスクがスレッドをブロックしない同時プログラミングの一種です。 asyncio は Python の非同期プログラミング用のライブラリで、プログラムがメイン スレッドをブロックせずに I/O 操作を実行できるようにします。イベント ループ asyncio の中核は、I/O イベントを監視し、対応するタスクをスケジュールするイベント ループです。コルーチンの準備が完了すると、イベント ループは I/O 操作を待つまでそのコルーチンを実行します。その後、コルーチンを一時停止し、他のコルーチンの実行を継続します。コルーチン コルーチンは、実行を一時停止および再開できる関数です。 asyncdef キーワードは、コルーチンの作成に使用されます。コルーチンは await キーワードを使用して、I/O 操作が完了するのを待ちます。 asyncio の次の基本

Golang コルーチンとゴルーチンの関係 Golang コルーチンとゴルーチンの関係 Apr 15, 2024 am 10:42 AM

コルーチンはタスクを同時に実行するための抽象的な概念であり、ゴルーチンはコルーチンの概念を実装する Go 言語の軽量スレッド関数です。この 2 つは密接に関連していますが、Goroutine のリソース消費量は少なく、Go スケジューラによって管理されます。 GoroutineはWebリクエストの同時処理やプログラムのパフォーマンス向上など、実戦で広く活用されています。

Python 非同期プログラミング: 非同期コードで効率的な同時実行性を実現する方法 Python 非同期プログラミング: 非同期コードで効率的な同時実行性を実現する方法 Feb 26, 2024 am 10:00 AM

1. 非同期プログラミングを使用する理由は何ですか?従来のプログラミングではブロッキング I/O が使用されます。つまり、プログラムは操作が完了するまで待機してから続行します。これは単一のタスクではうまく機能する可能性がありますが、多数のタスクを処理する場合にはプログラムの速度が低下する可能性があります。非同期プログラミングは、従来のブロッキング I/O の制限を破り、非ブロッキング I/O を使用します。つまり、プログラムは、タスクの完了を待たずに、タスクを別のスレッドまたはイベント ループに分散して実行できます。これにより、プログラムは複数のタスクを同時に処理できるようになり、プログラムのパフォーマンスと効率が向上します。 2. Python 非同期プログラミングの基礎 Python 非同期プログラミングの基礎は、コルーチンとイベント ループです。コルーチンは、関数の一時停止と再開を切り替えることができる関数です。イベントループはスケジュールを担当します

See all articles