PDA

View Full Version : سوالاتی در مورد thread



arefenayat
چهارشنبه 20 اسفند 1393, 09:23 صبح
سلام دوستان . از دوستانی که با thread کار کردند و یا اطلاعاتی دارند تقاضا می کنم کمک کنند .
من یه برنامه نوشتم که 1000 تا URL رو به عنوان ورودی میگیره و IP هاشون رو به ترتیب میده ، از اونجایی که با socket آی پی ها رو میگیرم زمان زیادی صرف میشه تا ip ها بدست بیاد .
حالا من اومدم و از thread استفاده کردم تو برنامه ام ، و برای اینکه سرعت برنامه ام افزایش پیدا کنه چند ترد رو همزمان استارت می کنم و روش زیر رو اجرا کردم ، نمیدونم شکل کارم درسته یا نه ولی به نظر خودم که نیست ، چون درست مفهوم مالتی تردینگ رو درک نکردم .


def mth1(self):
self.ui.start.setEnabled(False)
self.ui.pushButton.setEnabled(False)
self.th1=threading.Thread(target=self.getstr)
self.th1.start()
self.mth2()
self.mth3()
self.mth4()
self.mth5()
self.mth6()
self.mth7()
def mth2(self):
self.th2=threading.Thread(target=self.getstr)
self.th2.start()
def mth3(self):
self.th3=threading.Thread(target=self.getstr)
self.th3.start()
def mth4(self):
self.th4=threading.Thread(target=self.getstr)
self.th4.start()
def mth5(self):
self.th5=threading.Thread(target=self.getstr)
self.th5.start()
def mth6(self):
self.th6=threading.Thread(target=self.getstr)
self.th6.start()
def mth7(self):
self.th7=threading.Thread(target=self.getstr)
self.th7.start()


صرف نظر از اینکه برنامه کار میکنه ولی آیا روشی که من انتخاب کردم خوبه ؟ یعنی به تعداد مشخصی thread رو همزمان اجرا کنم آیا باعث افزایش سرعت میشه ؟ آیا این همون مفهوم مالتی تردینگ هست ؟

0x0ptim0us
چهارشنبه 20 اسفند 1393, 12:13 عصر
سلام
به نظر من شما میتونید کدتون رو بهتر از این در بیارد و چندتا نکته رو هم بنده ذکر کنم
اول اینکه شما کنترلی روی تعداد thread ندارید اگه برنامه شما کارهای معمولی رو داخل یک سیستم انجام میده مشکلی نیست ولی چون کار برنامه شما با اینترنت هست تعداد زیاد درخواست احتمال بروز timeout رو میده و چون برنامه قرار هست رو شبکه های مختلف اجرا بشه باید این رو کنترل کنید ...
دوم اینکه به نظر من بهتره یک کلاس جداگانه بنویسید که کار شما رو به صورت thread انجام بده
حالا من پایین یک مثال میزنم امیدوارم بتونه کمک کنه
فرض کنید من یه کلاس دارم که به صورت thread قراره یک یک عبارت رو بگیره و چاپ کنه ، عبارت های گوناگون که مثلا از یک فایل متنی میخونه چیزی که شبیه به کار شما هم باشه


class MyThread(threading.Thread):
def __init__(self, text):
threading.Thread.__init__(self)
self.mytext = text
def run(self):
print self.mytext

این میشه کلاس ما که یک ورودی میگیره همون text بعد میاد در داخل متغییر self.text قرار میده و میفرسته واسه فانکشن run که اونم واسه ما print میکنه ، این یه متد خوب واسه thread هست حالا ما میایم thread رو استارت میزنیم :


f = open("my_text_file.txt", "r").readlines()
for text in f:
t = MyThread(text)
t.start()


تو کد بالا هم ما میایم از فایل متنی text رو میگیریمو و میدیم به کلاس thread و start میکنیمش حالا اگه میخواین یه وقفه باشه بین هر thread میتونید قبل t.start() یه sleep کوچولو هم بزارید

اما برای اینکه شما کنترلی بر تعداد thread داشته باشین باید بیرون از کلاستون واسش تعریف کنید که من میخوام برای مثال 10 تا thread همزمان اجرا بشن و منتظر بمونن (به صورت کلی 10 تا thread همیشه در حال اجرا باشن)
برای اینکار شما میتونید از خصیصه BoundedSemaphore استفاده کنید برای مثال برای کد بالا :



threadLimiter = threading.BoundedSemaphore(10)

class MyThread(threading.Thread):
def __init__(self, text):
threading.Thread.__init__(self)
self.mytext = text
def run(self):


threadLimiter.acquire()
print self.mytext
threadLimiter.release()


فقط به threadLimiter.acquire() در ابتدای کار و threadLimiter.release() در انتهای کارتون توجه کنید که مشخص میکنند این thread فعلا مشغول هست و در انتهای کار threadLimiter.release() میاد thread رو آزاد میکنه برای thread بعدی ...

این چیزی بود که از دستم بر میامد اگه خواستین میتونید از سایت زیر که قرار میدم (که یکی از بهترین سایت ها در مورد کتابخونه های پایتون هست) مطالعه کنید :

http://pymotw.com/2/threading/

arefenayat
پنج شنبه 21 اسفند 1393, 07:38 صبح
سلام ، ممنون از توضیحات خوب و مفصلتون
از اونجایی که اولین باری هست که من دارم با Thread کار میکنم درکش یکم برام سخته
1-برای مثال شما فرض کنید من یه لیست باکس دارم که 10 تا آیتم توش داره ، و یه تابع دارم که وظیفه اش فراخوان کردن آیتم ها به صورت تک تک هست ، آیا اگر من 10 تا Thread بنویسم که همشون همزمان اون تابع رو اجرا کنند در این صورت مشکلی پیش میاد ؟
2-اصولا وقتی یه Thread روی لیست باکس من کار میکنه و مثلا آیتم 0 رو میخونه آیا Thread بعدی هم که همزمان در حال اجراست همون آیتم رو میخونه یا میره سراغ آیتم بعدی ؟
3-آیا امکانش هست که رفتار Thread ها کنترل بشه و چک کنیم آیا خواندن از لیست تمام شده یا خیر ؟
4-لطفا در مورد acquire و release توضیحی بدید
البته برای گرفتن پاسخ این سوالات خیلی داکیومنت های پایتون رو زیر و رو کردم ولی چیز خاصی دستگیرم نشد ، امیدم به شماهاست :کف:

0x0ptim0us
پنج شنبه 21 اسفند 1393, 10:20 صبح
سلام
در مورد سوال 1 و 2 ، خوب شما یک تابع دارین که داره لیست رو یکی یکی فراخوانی میکنه شما میتونید مثل مثال بالا از تابع بگیرید یکی یکی بدید thread تا براتون انجام بده، یا میتونید خیلی ساده از یه حلقه برای این کار استفاده کنید و ایتم به دست اومده رو پاس بدین به کلاس thread ...

در مورد سوال 3 بله میشه برای مثال :

import threadingimport time


def worker():
print threading.currentThread().getName(), 'Starting'
time.sleep(2)
print threading.currentThread().getName(), 'Exiting'


def my_service():
print threading.currentThread().getName(), 'Starting'
time.sleep(3)
print threading.currentThread().getName(), 'Exiting'


t = threading.Thread(name='my_service', target=my_service)
w = threading.Thread(name='worker', target=worker)
w2 = threading.Thread(target=worker) # use default name


w.start()
w2.start()
t.start()


خروجی :



worker Thread-1 Starting
my_service Starting
Starting
Thread-1worker Exiting
Exiting
my_service Exiting


توی مثال پست قبل من subclassing thread رو براتون توضیح داده به نظرم از این روش برید جلو بهتره هم کدتون منظم میشه و هم میتونید کنترل بهتری روی thread داشته باشین
در مورد سوال 4 یکم بحثش مفصل هست اما به طور ساده اگه بخوایم بگیم میشه کنترل دسترسی به منابع، ما یه خصیصه lock داریم توی همین threading که به شما اجازه میده منابعتون رو کنترل کنید برای مثال شما یک thread رو استارت میزنید و با استفاده از خصیصه lock میاید منابع اون thread رو lock میکنید (با استفاده از lock.acquire ) یهنی به thread بعدی میگید صبر کن threadقبلی منابع رو قفل کرده امکان استفاده نیست فعلا بعد وقتی شما یک thread رو release میکنید در اصل به thread بعدی امکان استفاده از منابع رو میدید ، این 2 خاصیت در اصل برای کنترل منابع به کار میره ، تو سایتی که بالا براتون لینک کردم تمامی این مباحث برسی شده

نکته بعدی اینکه کنترل thread تو برنامه های gui مشکلات خواص خودشو داره برای مثال اگه شما از کتابخونه pyside برای gui استفاده میکنید خودش QThread رو برای threading در اختیارتون قرار میده که نیازی نیست از کتابخانه hreading خود پایتون استفاده کنید اما برای tk و gtk+ شما مجبورید از threading استفاده کنید.

arefenayat
پنج شنبه 21 اسفند 1393, 17:47 عصر
سلام ، خسته نباشید ، خیلی ممنون از راهنماییتون
من طبق روشی که شما گفتید رفتم جلو ولی متاسفانه به مشکل بر خوردم
در حال حاضر من توی برنامه ام یک کلاس دارم که سازنده GUI من هست ، و طبق چیزی که شما توی تاپیک گفتید سعی کردم یک کلاس دیگه بسازم و اطلاعات رو به اون بفرستم تا Thread ها از طریق اون اطلاعات رو پردازش کنند . ولی به مشکل بر خوردم ، هر کاری میکنم نمیشه خصوصیات کلاس GUI ام رو توی کلاس Thread ام لود کنم ، GUI من PyQt هست ، مثلا میخوام از ListWidget که در کلاس Gui من با اسم self.ui.listwidget شناخته میشه مقدارش رو بخونم و اون رو توسط یک Thread در کلاسی دیگه پردازش کنم و + 2 کنم و مجددا نتیجه رو به اون listwidget اعمال کنم ولی هر کاری کردم نشد . لطفاً شما راهنمایی بفرمایید .
مثلا این کلا Gui من هست (خصوصیات توی یک فایل دیگه لود شده اند) ، من میخوام یک آیتم رو از لیست کم کنم و بفرستم سمت Thread و اونور +2 کنم و دوباره همونجا به لیست اضافش کنم .

class MyForm(QtGui.QDialog,threading.Thread):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_Dialog()
self.ui.setupUi(self)
def startprocess(self):
cx=int(self.ui.count.text())
for ii in range(cx) :
s=self.ui.listWidget.takeItem(0).text()
a=MyThread(s)
a.start()



اینم کلاس ترد

threadLimiter = threading.BoundedSemaphore(10)
class MyThread(threading.Thread):
def __init__(self, text):
threading.Thread.__init__(self)
self.mytext = text
def run(self):
threadLimiter.acquire()
a=self.mytext+2
self.ui.listWidget.AddItem(a)
threadLimiter.release()




اینجا اصلاً self.ui رو نمیشناسه ، البته این گزینه ها رو


class MyForm(QtGui.QDialog,threading.Thread):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_Dialog()




به کلاس ترد اضافه کردم ولی بازم کار نکرد.

n.nowroozi
جمعه 22 اسفند 1393, 12:34 عصر
اون شی ای که توی تردتون دیده نمیشه رو میتونید موقع فراخوانی پاس بدید اونوقت میبینه..
ولی در کل برا پروژه هایی که درخواست همزمان خیلی میاد سمت سرور به نظرم بهتره که از یک صف استفاده کنید و درخواستهارو تک تک از اون بگیرید میتونید یه نگاهی به celery بندازید.

0x0ptim0us
شنبه 23 اسفند 1393, 13:12 عصر
سلام
خوب کدتون اشتباه هست
من با توجه به کدی که گذاشته بودین یه کد نوشتم که کارتونو را بندازه اگه یه نگاهی بندازین مشکلتون حل میشه ایشالا (من تستش نکردم فقط از زوی کد شما ویرایشش کردم ولی به این روش بنویسین کارتون را میافته)


import threading

class MyForm(QtGui.QDialog):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_Dialog()
self.ui.setupUi(self)


def startprocess(self):
cx=int(self.ui.count.text())
for ii in range(cx) :
s=self.ui.listWidget.takeItem(0).text()
# inja ma mohtaviyate s ro midim be function preThread
self.preThread(s)

# in function faghat miyad s ro migire va thread ro start mikone vasamon
def preThread(self, s):
self.s = s
t = threading.Thread(target=self.myThread, args=(self.s,))
t.start()

def myThread(self, s):
print s

arefenayat
یک شنبه 24 اسفند 1393, 00:15 صبح
ممنون دوستان ، با وراثت درست شد .
فقط یه سوال ، اینی که توی تابع __init__ نوشته شده معنیش چیه ؟

threading.Thread.__init__(self)