Python3 多线程使用情况下详解,代理IP访问网站

系统 1497 0

Python3线程中常用的两个模块为**

_thread
threading(推荐使用)
每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

每个线程都有他自己的一组CPU寄存器,称为线程的上下文,该上下文反映了线程上次运行该线程的CPU寄存器的状态。
thread 模块已被废弃。用户可以使用 threading 模块代替。所以,在 Python3 中不能再使用"thread" 模块。为了兼容性,Python3 将 thread 重命名为 “_thread”。

_thread模块

#Python中调用_thread模块中的start_new_thread()函数产生新线程。_thread的语法如下:

            
               _thread.start_new._thread(function,args[,kwargs])

            
          

参数说明:
function - 线程函数。
args - 传递给线程函数的参数,他必须是个tuple类型。
kwargs - 可选参数。
#_thread模块除了产生线程外,还提供基本同步数据结构锁对象(lock object,也叫原语锁、简单锁、互斥锁、互斥量、二值信号量)。同步原语与线程管理是密不可分的。

案例1

            
              import _thread
from time import sleep
from datetime import datetime

date_time_format='%y-%M-%d %H:%M:%S'
def date_time_str(date_time):
    return datetime.strftime(date_time,date_time_format)

def loop_one():
    print('+++线程一开始于:',date_time_str(datetime.now()))
    print('+++线程一休眠4秒')
    sleep(4)
    print('+++线程一休眠结束,结束于:',date_time_str(datetime.now()))

def loop_two():
    print('***线程二开始于:',date_time_str(datetime.now()))
    print('***线程二休眠2秒')
    sleep(2)
    print('***线程二结束休眠,结束于:',date_time_str(datetime.now()))

def main():
    print('-----所有线程开始时间:',date_time_str(datetime.now()))
    _thread.start_new_thread(loop_one,())
    _thread.start_new_thread(loop_two,())
    sleep(6)
    print('-----所有线程结束时间:',date_time_str(datetime.now()))

if __name__=='__main__':
    main()

            
          

案例2

            
              import _thread
import time

#为线程定义一个函数
def print_time( threadName, delay):
   count = 0
   while count < 5:
      time.sleep(delay)
      count += 1
      print ("%s: %s" % ( threadName, time.ctime(time.time()) ))

#创建两个线程
try:
   _thread.start_new_thread( print_time, ("Thread-1", 2, ) )
   _thread.start_new_thread( print_time, ("Thread-2", 4, ) )
except:
   print ("Error: 无法启动线程")
while 1:  
   pass

            
          

#执行以上程后可以按下 ctrl-c to 退出。

#_thread模块提供了简单的多线程机制,两个循环并发执行,总的运行时间为最慢的线程的运行时间(主线程6s),而不是所有线程的运行时间之和。start_new_thread()要求至少传两个参数,即使想要运行的函数不要参数,也要传一个空元组。

#sleep(6)是让主线程停下来。主线程一旦运行结束,就关闭运行着的其他两个线程。这可能造成主线程过早或过晚退出,这时就要使用线程锁,主线程可认在两个子线程都退出后立即退出。

            
              import _thread
from time import sleep
from datetime import datetime
loops=[4,2]
date_time_format='%y-%M-%d %H:%M:%S'

def date_time_str(date_time):
    return datetime.strftime(date_time,date_time_format)
def loop(n_loop,n_sec,lock):
    print('线程(',n_loop,')开始执行:,date_time_str(datetime.now()),先休眠(',n_sec,')秒')
    sleep(n_sec)
    print('线程(',n_loop,')休眠结束,结束于:',date_time_str(datetime.now()))
    lock.release()
def main():
    print('---所有线程开始执行...')
    locks=[]
    n_loops=range(len(loops))
    for i in n_loops:
        lock=_thread.allocate_lock()
        lock.acquire()
        locks.append(lock)
    for i in n_loops:
        _thread.start_new_thread(loop,(i,loops[i],locks[i]))

    for i in n_loops:
        while locks[i].locked():
            pass

    print('---所有线程执行结束:',date_time_str(datetime.now()))

if __name__=='__main__':
    main()

            
          

线程模块

Python3 通过两个标准库 _thread 和 threading 提供对线程的支持。

_thread 提供了低级别的、原始的线程以及一个简单的锁,它相比于 threading 模块的功能还是比较有限的。

threading 模块除了包含 _thread 模块中的所有方法外,还提供的其他方法:

threading.currentThread(): 返回当前的线程变量。
threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
除了使用方法外,线程模块同样提供了Thread类来处理线程,Thread类提供了以下方法:

run(): 用以表示线程活动的方法。
start():启动线程活动。
join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。
isAlive(): 返回线程是否活动的。
getName(): 返回线程名。
setName(): 设置线程名。

使用 threading 模块创建线程

我们可以通过直接从 threading.Thread 继承创建一个新的子类,并实例化后调用 start() 方法启动新线程,即它调用了线程的 run() 方法:

            
              import threading
import time

exitFlag = 0

class myThread (threading.Thread):
    def __init__(self, threadID, name, counter):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.counter = counter
    def run(self):
        print ("开始线程:" + self.name)
        print_time(self.name, self.counter, 5)
        print ("退出线程:" + self.name)

def print_time(threadName, delay, counter):
    while counter:
        if exitFlag:
            threadName.exit()
        time.sleep(delay)
        print ("%s: %s" % (threadName, time.ctime(time.time())))
        counter -= 1

# 创建新线程
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)

# 开启新线程
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print ("退出主线程")

            
          

线程同步

如果多个线程共同对某个数据修改,则可能出现不可预料的结果,为了保证数据的正确性,需要对多个线程进行同步。

使用 Thread 对象的 Lock 和 Rlock 可以实现简单的线程同步,这两个对象都有 acquire 方法和 release 方法,对于那些需要每次只允许一个线程操作的数据,可以将其操作放到 acquire 和 release 方法之间。如下:

多线程的优势在于可以同时运行多个任务(至少感觉起来是这样)。但是当线程需要共享数据时,可能存在数据不同步的问题。

考虑这样一种情况:一个列表里所有元素都是0,线程"set"从后向前把所有元素改成1,而线程"print"负责从前往后读取列表并打印。

那么,可能线程"set"开始改的时候,线程"print"便来打印列表了,输出就成了一半0一半1,这就是数据的不同步。为了避免这种情况,引入了锁的概念。

锁有两种状态——锁定和未锁定。每当一个线程比如"set"要访问共享数据时,必须先获得锁定;如果已经有别的线程比如"print"获得锁定了,那么就让线程"set"暂停,也就是同步阻塞;等到线程"print"访问完毕,释放锁以后,再让线程"set"继续。

经过这样的处理,打印列表时要么全部输出0,要么全部输出1,不会再出现一半0一半1的尴尬场面。
实例:

            
              import threading
import time

class myThread (threading.Thread):
    def __init__(self, threadID, name, counter):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.counter = counter
    def run(self):
        print ("开启线程: " + self.name)
        # 获取锁,用于线程同步
        threadLock.acquire()
        print_time(self.name, self.counter, 3)
        # 释放锁,开启下一个线程
        threadLock.release()

def print_time(threadName, delay, counter):
    while counter:
        time.sleep(delay)
        print ("%s: %s" % (threadName, time.ctime(time.time())))
        counter -= 1

threadLock = threading.Lock()
threads = []

# 创建新线程
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)

# 开启新线程
thread1.start()
thread2.start()

# 添加线程到线程列表
threads.append(thread1)
threads.append(thread2)

# 等待所有线程完成
for t in threads:
    t.join()
print ("退出主线程")

            
          

线程优先级队列( Queue)

Python 的 Queue 模块中提供了同步的、线程安全的队列类,包括FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列 PriorityQueue。

这些队列都实现了锁原语,能够在多线程中直接使用,可以使用队列来实现线程间的同步。

Queue 模块中的常用方法:

Queue.qsize() 返回队列的大小
Queue.empty() 如果队列为空,返回True,反之False
Queue.full() 如果队列满了,返回True,反之False
Queue.full 与 maxsize 大小对应
Queue.get([block[, timeout]])获取队列,timeout等待时间
Queue.get_nowait() 相当Queue.get(False)
Queue.put(item) 写入队列,timeout等待时间
Queue.put_nowait(item) 相当Queue.put(item, False)
Queue.task_done() 在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一个信号
Queue.join() 实际上意味着等到队列为空,再执行别的操作

            
              import queue
import threading
import time

exitFlag = 0

class myThread (threading.Thread):
    def __init__(self, threadID, name, q):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.q = q
    def run(self):
        print ("开启线程:" + self.name)
        process_data(self.name, self.q)
        print ("退出线程:" + self.name)

def process_data(threadName, q):
    while not exitFlag:
        queueLock.acquire()
        if not workQueue.empty():
            data = q.get()
            queueLock.release()
            print ("%s processing %s" % (threadName, data))
        else:
            queueLock.release()
        time.sleep(1)

threadList = ["Thread-1", "Thread-2", "Thread-3"]
nameList = ["One", "Two", "Three", "Four", "Five"]
queueLock = threading.Lock()
workQueue = queue.Queue(10)
threads = []
threadID = 1

#创建新线程
for tName in threadList:
    thread = myThread(threadID, tName, workQueue)
    thread.start()
    threads.append(thread)
    threadID += 1

#填充队列
queueLock.acquire()
for word in nameList:
    workQueue.put(word)
queueLock.release()

#等待队列清空
while not workQueue.empty():
    pass

#通知线程是时候退出
exitFlag = 1

#等待所有线程完成
for t in threads:
    t.join()
print ("退出主线程")

            
          

python之多线程

https://www.cnblogs.com/smallmars/p/7149507.html

            
              #coding=utf-8
import threading  # 导入threading包
from time import sleep
import time

def task1():
    print("Task 1 executed.")
    sleep(1)

def task2():
    print("Task 2 executed.")
    sleep(5)

print("多线程:")
starttime = time.time();  # 记录开始时间
threads = []  # 创建一个线程列表,用于存放需要执行的子线程
t1 = threading.Thread(target=task1)  # 创建第一个子线程,子线程的任务是调用task1函数,注意函数名后不能有()
threads.append(t1)  # 将这个子线程添加到线程列表中
t2 = threading.Thread(target=task2)  # 创建第二个子线程
threads.append(t2)  # 将这个子线程添加到线程列表中

for t in threads:  # 遍历线程列表
    t.setDaemon(True)  # 将线程声明为守护线程,必须在start() 方法调用之前设置,如果不设置为守护线程程序会被无限挂起
    t.start()  # 启动子线程
endtime = time.time();  # 记录程序结束时间
totaltime = endtime - starttime;  # 计算程序执行耗时
print("耗时:{0:.5f}秒".format(totaltime));  # 格式输出耗时
print('---------------------------')

#以下为普通的单线程执行过程,不需解释
print("单线程:")
starttime = time.time();
task1();
task2();
endtime = time.time();
totaltime = endtime - starttime;
print("耗时:{0:.5f}秒".format(totaltime));


            
          

伪装好了才能出发,通过proxy代理IP访问网站,python爬虫(1)

            
              from urllib.request import Request, build_opener
from fake_useragent import UserAgent
from urllib.request import ProxyHandler
url = "http://httpbin.org/get"
headers={
 "User-Agent": UserAgent().chrome
}
request = Request(url, headers=headers)
handler = ProxyHandler({"http" : "112.85.129.8:9999"})
opener = build_opener(handler)
response = opener.open(request)
print(response.read().decode())


            
          

通过ajax请求获得信息,没想到应用范围如此广,python爬虫(2)

            
              from urllib.request import Request, urlopen
from fake_useragent import UserAgent
base_url ="https://movie.douban.com/j/search_subjects?type=tv&tag=%E7%83%AD%E9%97%A8&page_limit=50&page_start={}"
i = 0
while True:
 headers = {
 "User-Agent": UserAgent().chrome
 }
 url = base_url.format(i * 20)
 request = Request(url, headers=headers)
 response = urlopen(request)
 info = response.read().decode()
 print(info)
 if info == "" or info is None or i==10:
 print("got all of data")
 break
 i += 1
 print("get "+ str(i) + " page")

            
          

3分钟搞定一个爬虫,贴吧爬虫就是这么简单,python爬虫(3)

            
              from urllib.request import Request, urlopen
from urllib.parse import urlencode
from fake_useragent import UserAgent
def get_html(url):
 headers = {
 "User-Agent": UserAgent().chrome
 }
 request =Request(url, headers=headers)
 response = urlopen(request)
 print(response.read().decode())
 return response.read()
def save_html(filename, html_bytes):
 with open(filename, "wb" ) as f:
 f.write(html_bytes)
def main():
 content = input("下载内容:")
 number = input("下载页面:")
 base_url = "https://tieba.baidu.com/f?ie=utf-8&{}"
 for pn in range(int(number)):
 args = {
 "pn": pn*50,
 "kw": content
 }
 args = urlencode(args)
 filename = "第" + str(pn) + "页.html"
 print("正在下载"+filename)
 html_bytes = get_html(base_url.format(args))
 save_html(filename, html_bytes)
if __name__ == '__main__':
 main()

            
          

request请求中进行url转码,结果意想不到,python爬虫(4)

            
              from urllib.request import Request, urlopen
from urllib.parse import urlencode
parameters={"wd":"你好"}
url = "https://www.baidu.com/s?wd={}".format(urlencode(parameters))
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}
request = Request(url, headers=headers)
response = urlopen(request)
print(response.read().decode())

            
          

闲着会生病的,玩玩python吧,python爬虫(5)

            
              from urllib.request import urlopen
from urllib.request import Request
from random import choice
url = "http://www.baidu.com"
user_agents = [
"Mozilla/5.0(compatible;MSIE9.0;WindowsNT6.1;Trident/5.0",
"Opera/9.80(WindowsNT6.1;U;en)Presto/2.8.131Version/11.11",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"]
headers = {"User-Agent": choice(user_agents)}
request = Request(url, headers=headers)
print(request.get_header('User-agent'))
response = urlopen(request)
info = response.read()
#print(info)

            
          

更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论