gil锁
money = 0
def add():
global money
for x in range(100000):
money+=1
def desc():
global money
for x in range(100000):
money -=1
import threading
thread1 = threading.Thread(target=add)
thread2 = threading.Thread(target = desc)
thread1.start()
thread2.start()
print(money)
#输出值
36631
39682
等等诸多的随机值
这是因为什么呢,多线程中如果对全局变量同时操作,会引起这种情况,gil锁会根据执行的字节码行数以及时间片释放gil 在涉及到io操作的时候主动释放,
多线程编程 - threading
#对于io操作来说,多线程与多进程性能差别不大
#通过Thread实例化
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(2)
print("get detail url end")
thread1 = threading.Thread(target=get_detail_html ,args = ("",))
thread2 = threading.Thread(target=get_detail_url ,args = ("",))
thread1.setDaemon(True)守护线程如果这儿的值为,等到`主线程`结束的时候会被killi掉
thread1.setDaemon(True)#守护线程如果这儿的值为,等到主线程结束的时候会被killi掉
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print("end")
上方的thread1.setDaemon(True)
如果主线程早于thread1线程结束的话那么此线程,会被销毁,如果早于主线程结束 那么主线程不会对thread1产生影响。
join
方法中意思与上方的相反,意思是之后执行完当前用jion方法的线程之后才会运行下方的代码
上方的创建线程的方法应用于较小的程序,相对于较大的程序还有如下创建线程的一种方法
#通过继承Thread来实现多线程
import threading
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")
thread1 = GetDetailHtml("111")
thread1.start()
print("end")
线程间通信 - 共享变量和 Queue
共享变量 (不安全)并不太安全
#线程间通信
#1线程通讯方式 共享变量
detail_url_list =[]
import time
import threading
def get_detail_html(url):
#爬去文章的详情页
global detail_url_list
url = detail_url_list.pop() #从队列尾部弹出数据
print("get detail html started")
time.sleep(2)
print("get detail html end")
def get_detail_url(url):
global detail_url_list
#爬取文章列表页
print("get detail url started")
time.sleep(4)
for i in range(20):
detail_url_list.append(i)
print("get detail url end")
thread_detail_url = threading.Thread(target= get_detail_url)
thread_detail_html =threading.Thread(target= get_detail_html)
print("end")
condition 使用
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()
#通过condition完成协同读诗
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()