多线程、多进程

python中的GIL

# GIL global interpreter lock 全局解释器锁
# python中的一个线程对应于c语言中的一个线程
# gil使得一个时刻只有一个线程在一个cpu上执行字节码,无法将多个线程映射到多个cpu上执行

# gil会根据字节码行数以及时间片释放gil,gil在遇到io的操作的时候主动释放

python多线程编程

普通样式的多线程编程

import threading
import time

def Get_Html():
    print("我开始爬取网页了")
    time.sleep(2)
    print("网页爬取完成")

def Get_Url():
    print("我开始爬取URL")
    time.sleep(4)
    print("URL爬取完成")

if __name__ == "__main__":
    thread1 = threading.Thread(target=Get_Html)
    thread2 = threading.Thread(target=Get_Url)

    start_time = time.time()

    # setDaemon方法是将该进程设置成主线程的守护进程,即如果主线程运行完成,该子线程必须结束
    # 该方法必须要在start方法之前设置
    # 该方法默认为False
    thread1.setDaemon(True) 
    thread2.setDaemon(True)

    thread1.start()
    thread2.start()

    thread1.join() # 该方法会让主线程等待子线程全部运行完成后,才会运行下面的代码
    thread2.join()

    print("工作完成,用时{}".format(time.time() - start_time))

使用继承方法实现多线程

import threading


class GetDetaiHtml(threading.Thread):
    """
    类继承Thread类必须重写run方法
    """
    def __init__(self, name):
        super().__init__(name = name)

    def run(self):
        print("我开始爬取{}网页了".format(self.name))
        time.sleep(2)
        print("网页爬取完成")

class GetDetaiUrl(threading.Thread):
    def __init__(self, name):
        super().__init__(name = name)

    def run(self):
        print("我开始爬取{}URL".format(self.name))
        time.sleep(4)
        print("URL爬取完成")

if __name__ == "__main__":
    thread1 = GetDetaiHtml("百度")
    thread2 = GetDetaiUrl("贴吧")

    thread1.start()
    thread2.start()

    thread1.join()
    thread2.join()

    print("运行完成")

线程间通信-Queue

线程间通信的两种方式:
共享变量
Queue

共享变量

import time
import threading

detail_url_list = [] # 共享变量

def get_detail_html(detail_url_list):
    # 爬取文章详情页
    while True:
        if len(detail_url_list):
            url = detail_url_list.pop() # pop() 函数用于移除列表中的一个元素(默认最后一个元素),并且返回该元素的值。
            print('我开始获取http:/{url}中的详情'.format(url = url))
            time.sleep(2)
            print('http:/{url}中的详情爬取完成'.format(url = url))

def get_detail_url(detail_url_list):
    # 爬取文章列表
    while True:
        print('开始获取文章url')
        time.sleep(4)
        for i in range(20):
            detail_url_list.append(i)
        print('获取文章url结束')

if __name__ == "__main__":
    thread1 = threading.Thread(target=get_detail_html, args=detail_url_list)
    thread2 = threading.Thread(target=get_detail_url, args=detail_url_list)

    thread1.start()
    thread2.start()

    thread1.join()
    thread2.join()

    print('网页爬取完成')

Queue

import time
from queue import Queue
import threading

def get_detail_html(queuq):
    # 爬取文章详情页
    while True:
        url = queuq.get() # pop() 函数用于移除列表中的一个元素(默认最后一个元素),并且返回该元素的值。
        print('我开始获取http:/{url}中的详情'.format(url = url))
        time.sleep(2)
        print('http:/{url}中的详情爬取完成'.format(url = url))

def get_detail_url(queue):
    # 爬取文章列表
    while True:
        print('开始获取文章url')
        time.sleep(4)
        for i in range(20):
            queue.put(i)
        print('获取文章url结束')

if __name__ == "__main__":

    detail_url_queue = Queue(maxsize=1000)

    thread1 = threading.Thread(target=get_detail_html, args=(detail_url_queue, ))
    for i in range(10):
        thread2 = threading.Thread(target=get_detail_url, args=(detail_url_queue, ))
        thread2.start()

    thread1.start()

    # 这两个命令是成对出现的
    # q.task_done(),每次从queue中get一个数据之后,当处理好相关问题,最后调用该方法,以提示q.join()是否停止阻塞,让线程向前执行或者退出;
    # q.join(),阻塞,直到queue中的数据均被删除或者处理。为队列中的每一项都调用一次。
    detail_url_queue.task_done()
    detail_url_queue.join()

    print('网页爬取完成')

线程同步(Lock、RLock、semaphores、Condition)

Lock

'''
    多线程操作全局变量 使用互斥锁
    重点:声明一个全局互斥锁
	
	1.用锁会影响性能
	2.锁会引起死锁
	3.
'''
import threading
import time
 
counter = 0
mutex = threading.Lock()
 
class MyThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
 
    def run(self):
        global counter, mutex
        time.sleep(1);
        if mutex.acquire():
            counter += 1
            print "I am %s, set counter:%s" % (self.name, counter)
            mutex.release()
 
if __name__ == "__main__":
    for i in range(0, 100):
        my_thread = MyThread()
        my_thread.start()

RLock 可重复的锁

'''
在一个线程里面,可以连续调用多次acquire
一定要注意acquire的次数和release次数一样
'''

Condition 条件变量,用于复杂的线程间同步


concurrent线程池编码

多进程编程-multiprocessing

进程间通信

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值