עבודה בתהליך משני (Thread / Task) ובכל זאת ה-UI תקוע
-
אני מבין שאתה רוצה בדרך הא' לשלוח פרמטר כל פעם למודת המשך אחרת. זה אפשרי בקלות, אלא שאני חושש להתאמץ בלי להיות בטוח בתכנון שלך.
אני מבין/משער/מנחש שהתודות Query וגם BeforeQuery הם גנריות. ויש מתודות רבות שקוראים להם כל אחת עם שאילתה שונה ועם טיפול המשך שונה. כמו"כ אני משער שתמיד הערך הנדרש אחרי הביצוע הוא DataSet. האם אני צודק?בינתיים, שים לב שבדרך הב' מתבצע בדיוק התיאור שלך "האם יש דרך לקרוא לתהליך מתוך שגרה, לחכות עם החזרת השליטה עד לאחר גמר ביצוע התהליך, ולהמשיך את אותה השגרה.", לא כן?
פורסם במקור בפורום CODE613 ב05/12/2017 03:14 (+02:00)
-
אכן צדקת - ישנן מתודות שונות שקוראות למתודות הגנריות "beforeQuery" ו- "query", וממשיכות כל אחת בצורה אחרת,
אם כי ספציפית ה-DataSet מתמלא כבר בתוך מתודת השאילתא "query" הגנרית, מכיון שהוא באמת נדרש בכל המתודות.
אבל עדיין יתכן טיפול שונה בין המתודות גם לא לאחר DataSet - במידה והשאילתא נתקעה.
שאז לדוגמא, מתודה אחת תצעק אין מסדי נתונים, בעוד שהשניה תצעק שאין נתונים בטבלה.לגבי הדרך הב',
אם מתודת ה Async רק מפעילה עם Await את מתודת השאילתא ובזה היא סיימה את עבודתה,
והמתודות שקוראות למתודת ה-Async הן אלו שממשיכות את הטיפול - חזרנו לאותה בעייה, שהן ממשיכות מיד ולא מחכות (בדקתי את זה).
ואם אני כותב את משפטי הטיפול שלאחר השאילתא בתוך מתודת ה Async (איפה שסימנת את 3 הנקודות בתור המיקום להמשך הטיפול),
שוב חזרנו לבעייה שהמשך הטיפול אמור להיות שונה בין המקרים.**תודה רבה!**אני מקווה שאני לא גורם לך נדודי שינה עם ה"קלוץ קאשעס" שלי
פורסם במקור בפורום CODE613 ב05/12/2017 03:30 (+02:00)
-
אז ניסוח השאלה הוא כזה:
איך אני כותב פונקציה שמרכזת פעולות ארוכות בטריד חיצוני (ויש לה עדיין פונקציונליות לפני ואחרי ההפעלה שכן מאוגדים לUI כמו הויזיבל pbarLoad), אבל מאפשר למתודה הקוראת אליהם להגדיר מה יתבצע אחרי שטריד יסתיים.
(שים לב לסוגריים דלעיל כי לולי הם תעביר את הקריאה לטריד ישירות לכל אירוע לחצן. ולק"מ.)
יש מאה מליון אפשרויות, מתחיל בדרך הב', איפה שאחזנו:Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click RunQuery("SELECT 8 FROM BIG_TABLE", Sub(ds) If ds.Tables.Count = 0 OrElse ds.Tables(0).Rows.Count = 0 Then MessageBox.Show("!!!") Else DataGridView1.DataSource = ds.Tables(0) End If End Sub) End Sub Private Async Sub RunQuery(command As String, doAfter As Action(Of DataSet)) pbarLoad.Visible = True Dim ds = Await Task.Run(Function() query(command)) pbarLoad.Visible = False doAfter(ds) End Sub Private Function query(command As String) As DataSet conn.Open() command.Connection = conn command.CommandText = queryString dataAdapter.SelectCommand = command() Dim ds As New DataSet dataAdapter.Fill(ds) conn.Close() Return ds End Function
אפשר לעשות אותו רעיון עם אפשרות א'. אבל אפשרות ב' היא יותר נוכנה כיום, אז למה לא נלך איתה וזהו.
שים לב שקצת שיניתי פה כמה דברים כי פשוט אני לא יכול לכתוב לפי הראש שלך בלי לראות הכל, והכי טוב שאתה תכתוב לפי הראש שליפורסם במקור בפורום CODE613 ב05/12/2017 03:36 (+02:00)
-
בס"ד
הפעם זה כבר נשמע מעניין ממש,
רק שהעיניים שלי נעצמות מאליהן... :roll:אם הצלחתי לקלוט את הלוגיקה של מה שכתבת,
אז באמת נראה שזה פותר את הבעייה יפה,
בעז"ה אחרי שיעברו חבלי שינה מעיני אבדוק הכל ואעדכן בל"נ.תודה רבה!!!
פורסם במקור בפורום CODE613 ב05/12/2017 03:54 (+02:00)
-
בס"ד
ובכן, הרעיון להכניס ללמבדה את כל "המשך הטיפול" ולשלוח אותה למתודת ה-Async כארגומנט - אכן עושה את העבודה. תודה רבה!
וברשותך ר' @דוד ל.ט., שתי שאלות שנולדו לי בעקבות הפתרון:
**א.**בדוגמא שהכנת, אתה יוצר את ה-DataSet מתוך פונקציית תהליך המשנה, ומחזיר אותו למתודת ה-Async.
האם לאחר שמתודת ה Async סיימה את פעילותה, עדיין אוכל לגשת ל DataSet לצורך בדיקה אם השתנו בו דברים, ואם כן לעדכן אותם במסד?
כי איך שאני עשיתי עד עכשיו, הגדרתי את ה DataSet כמשתנה גלובלי בשם result, ודרכו תיקשרתי עם המסד - מכל מתודה בתוכנה, כגון:dataAdapter.Update(result) ' לשמירת השינויים שנעשו בדטה גרידאו: If result.GetChanges IsNot Nothing Then ' מציע למשתמש לשמור שינויים לפני הפעלת שאילתא חדשה
ב. האם יש דרך להשתמש במתודת ה-Async כפונקצייה במקום שגרה, בכדי שאוכל להחזיר ערך בוליאני שיודיע על כשל באמצע?
כמובן שתמיד ניתן ליצור משתנה גלובלי שיקבל false בתחילת השגרה וישתנה ל true בסופה, אבל בשביל זה יש פונקצייה, לא?
ניסיתי להגדיר את ה-Async כפונקצייה מסוג Task(Of Boolean), ולבדוק במתודה שקראה לה את תוצאת ה AsyncQuery.Result,
אבל כשזה מוגדר כך, אז פונקציית ה Async נתקעת ולא ממשיכה - בשלב שהתהליך שהיא מריצה מסיים את פעולתו.תודה רבה!!!
פורסם במקור בפורום CODE613 ב05/12/2017 22:42 (+02:00)
-
בקשר לא', כתבתי לך
@דוד ל.ט.שים לב שקצת שיניתי פה כמה דברים כי פשוט אני לא יכול לכתוב לפי הראש שלך בלי לראות הכל, והכי טוב שאתה תכתוב לפי הראש שלי
אין שום בעיה להשתמש במשתנה בסקופ גבוה ולשתף אותו וזה גם נחוץ לפעמים רק שים לב האם זה לא יכול לעשות תוצאות קצת משונות (טעינה כפולה של טבלה ועוד).
בקשר לב', היית יכול לעשות ככה:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click RunQuery("SELECT 8 FROM BIG_TABLE", Sub(hasSuccess) If Not hasSuccess Then 'error Else If result.Tables.Count = 0 OrElse result.Tables(0).Rows.Count = 0 Then MessageBox.Show("!!!") Else DataGridView1.DataSource = result.Tables(0) End If End Sub) End Sub Private Async Sub RunQuery(command As String, doAfter As Action(Of Boolean)) pbarLoad.Visible = True Dim ds = Await Task.Run(Function() query(command)) pbarLoad.Visible = False doAfter(ds) End Sub Private Function query(command As String) As Boolean conn.Open() command.Connection = conn command.CommandText = queryString dataAdapter.SelectCommand = command() Try dataAdapter.Fill(result) Catch Return False End Try conn.Close() Return True End Function
אבל אני חושב שזה לא טוב לעשות ככה. לפעמים תצטרך לדעת את השגיאה ועוד.
תוכל לעשות try מסביב למתודה האסינכורנית (הAwait) או לנהל את השגיאה בתוך התהליך ולשלוח את השגיאה בתוצאה (באובייקט שמכיל גם Exception). אבל באמת אני לא יודע מה הRight Way בהתנהלות מול שגיאות בasync.פורסם במקור בפורום CODE613 ב05/12/2017 23:36 (+02:00)
-
אני מאוד השתעבדתי לצורת הפעולה שלך, אם הכל היה תלוי בי הייתי עושה ככה:
Dim dataSet As DataSet Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click UiBefore() Try Dim result = Await Query("SELECT 8 FROM BIG_TABLE") dataSet = result If result.Tables.Count = 0 OrElse result.Tables(0).Rows.Count = 0 Then MessageBox.Show("!!!") Else DataGridView1.DataSource = result.Tables(0) End If Catch ex As Exception 'erro End Try UiAfter() End Sub Private Function query(command As String) As DataSet Using conn As New SqlConnection Using da As New SqlDataAdapter(command, conn) conn.Open() Dim ds As New DataSet da.Fill(ds) Return ds End Using End Using End Function Private Sub UiBefore() pbarLoad.Visible = True End Sub Private Sub UiAfter() pbarLoad.Visible = False End Sub
ככה אין "מקום מרוכז" סינכרוני שמריץ שאילתות, אלא כל אירוע לחיצת כפתור כולל את רוב העבודה חוץ משאילתה עצמה.
ככה גם לא צריך למבדות. יש עוד כמה נושאים פה לדיון. אני חייב להודות שהראש שלך פיקח מידי וממילא אתה מוצא את עצמך בשאלות תכנוניות די מתקדמות בשלב מוקדם למדי.פורסם במקור בפורום CODE613 ב05/12/2017 23:56 (+02:00)
-
תודה על תשובתך!
בקשר לב',
דווקא לשגיאות בתוך התהליך כבר עכשיו זה מנוהל מתוך מתודת התהליך עצמו,
אבל עיקר השאלה ששאלתי זה למקרה של עצירת מתודת ה-Async עוד לפני שהיא מגיעה לשלב של התהליך.למשל,
בתחילת מתודת ה-Async, היא בודקת אם מולאו הנתונים בשדות של: כתובת השרת-יוזר-סיסמא, ובמידה ולא - היא מודיעה על השגיאה, ומסתיימת.
כמובן, שבשלב זה, המתודה שקראה למתודת ה-Async שנכשלה, אמורה לדעת לעצור גם היא ולא להמשיך הלאה.עד ש"העלית אותי" על ה-Async, עשיתי את זה עם הפונקצייה BeforeQuery, שבמידה והיא נפלה באמצע - היא החזירה false.
השאלה אם יש דרך דומה להגדיר גם את מתודת ה-Async כ"פונקצייה", או אולי דרך אחרת בכלל?תודה רבה!!!
פורסם במקור בפורום CODE613 ב06/12/2017 00:00 (+02:00)
-
אני רואה שאנחנו עובדים בצורה אסינכורנית, תוך כדי שאתה כתבת תגובה חדשה - אני כתבתי תגובה לתגובתך הקודמת. :lol:
וואו, הרעיון שהעלית בתגובתך האחרונה - הוא אדיר, וכמובן שהוא מייתר לגמרי את תגובתי הקודמת שנכתבה לפני שראיתי את הרעיון שלך.
תודה רבה!!!
אגב,@דוד ל.ט.
אני חייב להודות שהראש שלך פיקח מידי
ביארת לי עכשיו פשט בברכות לא: את הסבר ר' דימי לבקשת חנה "ונתתה לאמתך זרע אנשים", שהוא מסביר שהיא ביקשה בן "... ולא חכם ..."
כמובן שזה לא יותר מבדיחותא בעלמא, "אין קשר בין המצולם לכתבה"...פורסם במקור בפורום CODE613 ב06/12/2017 00:38 (+02:00)
-
אז אחרי שהוצאתי את המיץ לכולם (למרות ש @דוד ל.ט. הבטיח שאין לי סיכוי לשגע את כולם, אני בטוח שהוא כבר עשה על זה חרטה בלב שלם ;))
"הזורעים בדמעה ברינה יקצורו" -
אני משאיר פה לכמה ימים את התוכנה המוכנה כולל קבצי קוד המקור, אולי יצא מזה משהו למישהו.אני אישית אמשיך לפתח את התוכנה לכיון יותר אישי,
של מניפולציה על CSV שהורדתי מ"גוגל קונטקטס" עם כל אנשי הקשר שלי,
והעלאתם למסד MySQL כששדות הנתונים מחולקים אחרת לגמרי מגוגל - לטובת המרכזייה הטלפונית שלי.אם בסופו של יום - כשמישהו מהחברים כאן - שבמקרה המספר שלו שמור אצלי באנשי הקשר (ויש כאן כמה כאלו) -
יתקשר אלי, ואני ארים את השיחה: @ניק-פלוני-אלמוני, מה נשמע?
אז תדעו לכם - שהכל בזכות הצדיקים דכאן, בלעדיהם כנראה הייתי ממשיך לחלום עד 120 על "ללמוד יום אחד SQL"...ובעז"ה אחרי שאשלים את פרוייקט הדטה בייס, אנסה להתחיל עם עולם ה WEB.
היכונו לשאלת השאלות עם איזה IDE הכי מומלץ להתחיל... :mrgreen:פורסם במקור בפורום CODE613 ב06/12/2017 18:51 (+02:00)
-
@דוד ל.ט.
ואגב, בשלב זה יש לך על מה לחשוב על api לcontact.
האמת, שהפעם הצלחת לבלבל אותי!רק בגלל מה שכתבת כאן, החלטתי בינתיים לוותר על הרעיון של ה-API לגוגל קונטקטס,
ולהתחיל "על אש נמוכה" - בלי סנכרון, אלא רק ייצוא חד פעמי של אנשי הקשר הנוכחיים לקובץ CSV והעלאתו למסד שלי.אז למעשה, אתה כן ממליץ לקפוץ למים וללכת על סנכרון מלא עם ה-API של גוגל?
תודה רבה!
פורסם במקור בפורום CODE613 ב06/12/2017 20:11 (+02:00)
-
האם הAPI לגוגל קריטי לך? כמה זה חשוב לך? ... אולי תעשה עדכון ידני פעם בחודש?
לטווח הקרוב, באמת לא קריטי. אפשר לעשות זאת ידני - כמו שדיברנו.
עיקר העניין הוא, שבפעם הבאה שתתקשר אלי, אזהה שזה אתה, ולא עוד איזה נודניק תורן...
ובנימה יותר רצינית,
יש לאשתי עסק זעיר, וחשוב לה היכולת לזהות לפני שהיא עונה - את הלקוחות שמגיע להם יחס X מול הלקוחות ש(לא) מגיע להם יחס Y...
ובשביל זה, ברור שאתה צודק שאין צורך ב-API ובסנכרון, ולכן התחלתי כבר לצעוד בכיוון הזה.אבל ברור, שאם אסתכל על זה "במשקפיים עסקיות",
אם אוכל להציע - ללקוחות שמקימים אצלי מערכת טלפונית - סנכרון עם אנשי הקשר שלהם,
ושכל טלפון שמגיע ממישהו שהם הכניסו באנשי הקשר שלהם - הם רואים על צג הטלפון במי מדובר - תוך כדי צלצול,
וודאי שזה יהיה מבחינתי שדרוג שמביא בכנפיו ברכה.
וכמובן, שבשביל להציע כזאת אפשרות, אני צריך סנכרון אוטומטי, ולא משהו ידני וחד פעמי. ובמילה אחת: API.פורסם במקור בפורום CODE613 ב07/12/2017 12:22 (+02:00)
-
@דוד ל.ט.
תעדכן.
כל הכבוד, אתגרת אותי לא רע!
מעולם לא נכנסתי רשמית לעולם של ה-API (למרות שהשתמשתי בזה מידי פעם - מבלי לדעת שזה בעצם API...),
וקל וחומר שלא הכרתי את ה-API המורכבים של גוגל,
בקיצר, התחלתי ללמוד את העניין (של איך מצליחים לתקשר עם גוגל, אל תדאג - לא שום דבר מעבר),
נראה לי שפחות או יותר קלטתי מי נגד מי ולמה,ואז...
ואז הגיע תורו של ויזואל סטודיו "להוציא לי קרניים" :twisted:
אני מנסה להוסיף את ה-API מה-NuGet (שעד השעות האחרונות חשבתי שזה קשור רק לעולם הקולינרי - במבה, דגני בוקר etc),
הוא מתחיל לשמור את הקבצים בתיקיית הפרויקט, ואז מוחק אותם שוב בתואנה:
An error occurred while writing file 'D:\BlaBla\kuku\packages.config': Failed to write packages.config as XML file 'D:\BlaBla\kuku\packages.config'. Error: 'Illegal characters in path'.
אציין רק, אין תווים בעברית ולא רווחים לאורך כל ה PATH של הפרויקט,
כמו כן, ניסיתי בשני מחשבים שונים, אחד עם VS 2015 והשני עם VS 2017. אותו דבר.
אם זה נפק"מ, אז המכנה המשותף בין המחשבים שמותקן עליהם Win 10 Fall Creators Update, והם גולשים דרך נטפרי. (ויש להם מסך :lol: )תודה רבה!
פורסם במקור בפורום CODE613 ב07/12/2017 19:37 (+02:00)
-
@דוד ל.ט.
ממש משונה. היה פה כבר כזה סיפור
viewtopic.php?f=1&t=194הלינק שבור, אבל לא נורא:
@דוד ל.ט.
פה אני רואה שיש כזה דבר בהגדרות תאריך עבריות:
תסלח לי שויתרתי על יצירת משתמש נוסף
החלפתי זמנית ללוח גרגוריאני, התקנתי, החזרתי ללוח עברי, ואני רץ למעריב...Successfully installed 'Google.Apis.Auth 1.31.0' to העלאת אנשי קשר של גוגל ל-MySQL ========== Finished ==========**הכל מעולה!**
דאאאאאויד!!! דאאאאאויד!!!
תודה רבה!!!פורסם במקור בפורום CODE613 ב07/12/2017 20:43 (+02:00)