線程
多任務簡單介紹
- 有很多事情在現實生活的場景中是同時進行的,比如開車的時候 手和腳共同來駕駛汽車,再比如唱歌跳舞也是同時進行的。
- 多任務,就是能夠在同一時間同時進行多個任務。
這樣同時進行多個任務,有一個極大的好處,那就是節省時間
代碼舉例
import time
import threading
def sing():
for i in range(5):
print("唱歌")
time.sleep(1)
def dance():
for i in range(5):
print("跳舞")
time.sleep(1)
t1 = threading.Thread(target=sing)
t2 = threading.Thread(target=dance)
t1.start()
t2.start()
import time
import threading
def sing():
for i in range(5):
print("唱歌")
time.sleep(1)
def dance():
for i in range(5):
print("跳舞")
time.sleep(1)
sing()
dance()
第一段代碼開啟3個線程,分別是主線程,子線程t1,子線程t2,耗時一共是5秒
第二段代碼開啟1個線程,那就是主線程,耗時一共是10秒
為什么第一段代碼耗時只要5秒,而第二段代碼耗時要10秒呢?
下面就由sunt來為大家說下原因吧,先分析第一段代碼:
主線程先開始運行,然后讓兩個小弟,也就是子線程t1,t2。分別去執行sing()和dance()代碼,這兩個小弟是並行執行的,並不是說小弟t1先執行完,
小弟t2才去執行,而是兩個小弟同時執行,故耗時為5秒,圖解如下:

打印出來結果:
唱歌
跳舞
跳舞
唱歌
跳舞
唱歌
跳舞
唱歌
跳舞
唱歌
這是因為當他們從休眠到喚醒是同時的,故資源掠奪的不確定性,有可能跳舞先執行,也有可能唱歌先執行,不過一定是成對出現的。
並行執行耗時總時間為5秒。
接下來分析第二段代碼:
主線程先開始執行,然后主線程執行sing()代碼塊,等待sing()代碼塊執行完之后,才開始執行dance()代碼塊。故耗時為sing()代碼塊
的時間加dance()代碼塊的時間,一共為10秒。圖解如下:

多任務的原理
什么叫“多任務”呢?簡單地說,就是操作系統可以同時運行多個任務。打個比方,你一邊在用瀏覽器上網,一邊在聽MP3,一邊在用Word趕作業,這就是多任務,至少同時有3個任務正在運行。還有很多任務悄悄地在后台同時運行着,只是桌面上沒有顯示而已。
單核cpu工作原理
- 現在,多核CPU已經非常普及了,但是,即使過去的單核CPU,也可以執行多任務。由於CPU執行代碼都是順序執行的,那么,單核CPU是怎么執行多任務的呢?
- 答案就是操作系統輪流讓各個任務交替執行,任務1執行0.01秒,切換到任務2,任務2執行0.01秒,再切換到任務3,執行0.01秒……這樣反復執行下去。實際上看,每個任務都是交替執行的,但是,由於CPU的執行速度實在是太快了,我們感覺就像所有任務都在同時執行一樣。
- 真正的並行執行多任務只能在多核CPU上實現,但是,由於任務數量遠遠多於CPU的核心數量,所以,操作系統也會自動把很多任務輪流調度到每個核心上執行。
多核cpu工作原理
和單核類似,相當於多了一個干活的人。
並發:指的是任務數多於cpu核數,通過操作系統的各種任務調度算法,實現用多個任務“一起”執行
(實際上總有一些任務不在執行,因為切換任務的速度相當快,看上去一起執行而已)
並行:指的是任務數小於等於cpu核數,即任務真的是一起執行的
- 並行和並發都算是多任務,但並行實際上才是真正的多任務,並發是假的。
線程的兩張創建方式
- 直接使用threading模塊的Thread類,指定要執行的方法,再調用start
- 使用繼承的方式,繼承Thread類,重新run方法,創建這個對象后,再調用start
查看當前程序線程數量
threading.enumerate()
- 獲取所有線程,返回的是一個列表。
- 如果需要個數,使用len(threading.enumerate())
為子線程傳遞參數
target方式
import time
import threading
def sing(nums):
for i in range(nums):
print("唱歌")
time.sleep(1)
def dance():
for i in range(5):
print("跳舞")
time.sleep(1)
t1 = threading.Thread(target=sing, args=(3,))
t2 = threading.Thread(target=dance)
t1.start()
t2.start()
類繼承方式
import threading
class Work1(threading.Thread):
def __init__(self, nums):
super().__init__()
self.nums = nums
def run(self):
for i in range(self.nums):
print("haha")
def main():
w = Work1(2)
w.start()
if __name__ == "__main__":
main()
Appium多端口
目標,讓一個腳本去跑到多台手機。
注意點: appium sever端口要不同,開啟多個。bootstrap端口要不同,開啟多個。udid需要指定,udid表示設備的唯一表示符號,通過 adb devices 查看。 前半部分都是,比如模擬器的(192.168.57.101:5555)。
appium server 和 bootstrap 和 udid 應該是成對出現的。
命令:
appium -p 4723 -bp 4724 -U 192.168.57.101:5555
-p 表示 appium的端口
-bp 表示 bootstrap的端口
-U 表示設備的標識符
修改init_driver讓,init_driver接受port的參數。並且進行對應的連接。
記得,創建的是不同的driver對象。
因為如果使用threading.Thread的這種形式,需要指定執行的函數,所以,把需要執行的代碼,封裝成一個函數。然后使用
ports = ["4723", "4725"]
for i in ports:
threading.Thread(target=do, args=(i,)).start()
來去執行創建多個driver並且進行腳本的操作。
下面看圖解就知道appium多端口的工作原理了。

依照上圖可以知道,如果要想讓一段腳本操作兩個手機,那么我要做的就是,開啟兩個appium服務和兩個bootstrap服務,並且端口號不能相同,
appium和bootstrap是一對,並且有兩個手機,還要指定手機設備號,故命令如下
appium -p 4723 -bp 4724 -U 192.168.57.101:5555
appium -p 4725 -bp 4726 -U 192.168.57.102:5555
代碼實現
命令行先啟動appium並指定端口,並指定bootstrap端口和手機設備號
appium -p 4723 -bp 4724 -U 192.168.57.101:5555
appium -p 4725 -bp 4726 -U 192.168.57.102:5555
base_driver.py
from appium import webdriver
def init_driver(port="4723"):
# server 啟動參數
desired_caps = dict()
# 設備信息
desired_caps['platformName'] = 'Android'
desired_caps['platformVersion'] = '5.1'
desired_caps['deviceName'] = '192.168.164.101:5555'
# app信息
desired_caps['appPackage'] = 'com.android.settings'
desired_caps['appActivity'] = '.Settings'
# 中文
desired_caps['unicodeKeyboard'] = True
desired_caps['resetKeyboard'] = True
# 不重置應用
desired_caps['noReset'] = True
# toast
# desired_caps['automationName'] = 'Uiautomator2'
# 聲明對象
driver = webdriver.Remote('http://localhost:' + port + '/wd/hub', desired_caps)
return driver
login_page.py
from base_action import BaseAction
class LoginPage(BaseAction):
pass
demo.py
import threading
from selenium.webdriver.common.by import By
from base_driver import init_driver
from base_action import BaseAction
from login_page import LoginPage
def do(port):
driver = init_driver(port)
login_page = LoginPage(driver)
if "4723" == port:
login_page.click((By.XPATH, "text,更多"))
else:
login_page.click((By.XPATH, "text,WLA"))
def main():
//根據ports不同,driver可以連接不同的手機
ports = ["4723", "4725"]
for i in ports:
threading.Thread(target=do, args=(i,)).start()
if __name__ == '__main__':
main()