この記事では Python のマルチスレッドについて詳しく紹介 (コード例) しています。一定の参考価値があります。困っている友人は参考にしてください。お役に立てれば幸いです。
グローバル インタプリタ ロック (cpython)
バイトコードの実行と同時に 1 つの CPU 上で実行されるスレッドは 1 つだけです (複数のスレッドを複数の CPU にマッピングすることはできません)
import dis def add(a): a = a + 1 return a print(dis.dis(add))
結果は毎回異なります。スレッド間のセキュリティの問題
##GIL は、直接コード行数または実行されたタイム スライスに基づいてリリースされます。リリースGILIO 操作が発生したときに積極的に解放するtotal = 0 def add(): #1. dosomething1 #2. io操作 # 1. dosomething3 global total for i in range(1000000): total += 1 def desc(): global total for i in range(1000000): total -= 1 import threading thread1 = threading.Thread(target=add) thread2 = threading.Thread(target=desc) thread1.start() thread2.start() thread1.join() thread2.join() print(total)
import time from threading import Thread def get_detail_html(url): print("get detail html started") time.sleep(2) print("get detail html end") def get_detail_url(url): print("get detail url started") time.sleep(4) print("get detail url end") if __name__ == '__main__': thread1 = Thread(target=get_detail_html, args=("",)) thread2 = Thread(target=get_detail_url, args=("",)) # 设置为守护线程 当主线程运行完时 子线程被kill掉 thread1.setDaemon(True) thread2.setDaemon(True) start_time = time.time() thread1.start() thread2.start() # 设置为阻塞 等待线程运行完再关闭主线程 thread1.join() thread2.join() # 默认情况下 主线程退出与时 子线程不会被kill掉 print("last time: {}".format(time.time() - start_time))
import time import threading def get_detail_html(url): print("get detail html started") time.sleep(2) print("get detail html end") def get_detail_url(url): print("get detail url started") time.sleep(4) print("get detail url end") #2. 通过集成Thread来实现多线程 class GetDetailHtml(threading.Thread): def __init__(self, name): super().__init__(name=name) def run(self): print("get detail html started") time.sleep(2) print("get detail html end") class GetDetailUrl(threading.Thread): def __init__(self, name): super().__init__(name=name) def run(self): print("get detail url started") time.sleep(4) print("get detail url end") if __name__ == "__main__": thread1 = GetDetailHtml("get_detail_html") thread2 = GetDetailUrl("get_detail_url") start_time = time.time() thread1.start() thread2.start() thread1.join() thread2.join() #当主线程退出的时候, 子线程kill掉 print ("last time: {}".format(time.time()-start_time))
# filename: thread_queue_test.py # 通过queue的方式进行线程间同步 from queue import Queue import time import threading def get_detail_html(queue): # 死循环 爬取文章详情页 while True: url = queue.get() # for url in detail_url_list: print("get detail html started") time.sleep(2) print("get detail html end") def get_detail_url(queue): # 死循环 爬取文章列表页 while True: print("get detail url started") time.sleep(4) for i in range(20): # put 等到有空闲位置 再放入 # put_nowait 非阻塞方式 queue.put("http://projectsedu.com/{id}".format(id=i)) print("get detail url end") # 1. 线程通信方式- 共享变量 if __name__ == "__main__": detail_url_queue = Queue(maxsize=1000) thread_detail_url = threading.Thread(target=get_detail_url, args=(detail_url_queue,)) for i in range(10): html_thread = threading.Thread(target=get_detail_html, args=(detail_url_queue,)) html_thread.start() start_time = time.time() # 调用task_down从主线程退出 detail_url_queue.task_done() # 从queue的角度阻塞 detail_url_queue.join() print("last time: {}".format(time.time() - start_time))
# 没有锁 def add1(a): a += 1 def desc1(a): a -= 1 """add 1. load a a = 0 2. load 1 1 3. + 1 4. 赋值给a a=1 """ """add 1. load a a = 0 2. load 1 1 3. - 1 4. 赋值给a a=-1 """ import dis print(dis.dis(add1)) print(dis.dis(desc1))
import threading from threading import Lock total = 0 # 定义一把锁 lock = Lock() def add(): global total global lock for i in range(1000000): # 获取锁 lock.acquire() total += 1 # 释放锁 lock.release() def desc(): global total for i in range(1000000): lock.acquire() total -= 1 lock.release() thread1 = threading.Thread(target=add) thread2 = threading.Thread(target=desc) thread1.start() thread2.start() thread1.join() thread2.join() print(total)
""" A(a、b) acquire (a) acquire (b) B(a、b) acquire (b) acquire (a) # 解决办法 B(a、b) acquire (a) acquire (b) """
import threading from threading import RLock total = 0 # 可重入锁 可以在同一个线程中可载入多次 lock = RLock() def add(lock): global total for i in range(1000000): # 获取锁 lock.acquire() lock.acquire() total += 1 do_something(lock) # 释放锁 lock.release() lock.release() def desc(): global total for i in range(1000000): lock.acquire() total -= 1 lock.release() def do_something(lock): lock.acquire() # do something lock.release() thread1 = threading.Thread(target=add) thread2 = threading.Thread(target=desc) thread1.start() thread2.start() thread1.join() thread2.join() print(total)
# 没有条件锁 不能实现对话 import threading class XiaoAi(threading.Thread): def __init__(self, lock): super().__init__(name="小爱") self.lock = lock def run(self): self.lock.acquire() print("{} : 在 ".format(self.name)) self.lock.release() self.lock.acquire() print("{} : 好啊 ".format(self.name)) self.lock.release() class TianMao(threading.Thread): def __init__(self, lock): super().__init__(name="天猫精灵") self.lock = lock def run(self): self.lock.acquire() print("{} : 小爱同学 ".format(self.name)) self.lock.release() self.lock.acquire() print("{} : 我们来对古诗吧 ".format(self.name)) self.lock.release() if __name__ == "__main__": cond = threading.Condition() xiaoai = XiaoAi(cond) tianmao = TianMao(cond) xiaoai.start() tianmao.start()
# 条件锁 import threading class XiaoAi(threading.Thread): def __init__(self, cond): super().__init__(name="小爱") self.cond = cond def run(self): with self.cond: self.cond.wait() print("{} : 在 ".format(self.name)) self.cond.notify() self.cond.wait() print("{} : 好啊 ".format(self.name)) self.cond.notify() self.cond.wait() print("{} : 君住长江尾 ".format(self.name)) self.cond.notify() self.cond.wait() print("{} : 共饮长江水 ".format(self.name)) self.cond.notify() self.cond.wait() print("{} : 此恨何时已 ".format(self.name)) self.cond.notify() self.cond.wait() print("{} : 定不负相思意 ".format(self.name)) self.cond.notify() class TianMao(threading.Thread): def __init__(self, cond): super().__init__(name="天猫精灵") self.cond = cond def run(self): with self.cond: print("{} : 小爱同学 ".format(self.name)) self.cond.notify() self.cond.wait() print("{} : 我们来对古诗吧 ".format(self.name)) self.cond.notify() self.cond.wait() print("{} : 我住长江头 ".format(self.name)) self.cond.notify() self.cond.wait() print("{} : 日日思君不见君 ".format(self.name)) self.cond.notify() self.cond.wait() print("{} : 此水几时休 ".format(self.name)) self.cond.notify() self.cond.wait() print("{} : 只愿君心似我心 ".format(self.name)) self.cond.notify() self.cond.wait() if __name__ == "__main__": from concurrent import futures cond = threading.Condition() xiaoai = XiaoAi(cond) tianmao = TianMao(cond) # 启动顺序很重要 # 在调用with cond之后才能调用wait或者notify方法 # condition有两层锁, 一把底层锁会在线程调用了wait方法的时候释放, # 上面的锁会在每次调用wait的时候分配一把并放入到cond的等待队列中, # 等到notify方法的唤醒 xiaoai.start() tianmao.start()
以上がPython マルチスレッドの詳細な紹介 (コード例)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。