branch: externals/el-job commit bc118ea0d089560deb72428bf6f54cfc90514ebe Author: Martin Edström <meedstro...@gmail.com> Commit: Martin Edström <meedstro...@gmail.com>
Style --- el-job-child.el | 14 ++++++------ el-job.el | 71 ++++++++++++++++++++++++++++++--------------------------- 2 files changed, 44 insertions(+), 41 deletions(-) diff --git a/el-job-child.el b/el-job-child.el index 6d8d04a1b9..0d06b3ba56 100644 --- a/el-job-child.el +++ b/el-job-child.el @@ -21,17 +21,17 @@ ;;; Code: -(defun el-job-child--zip (metalist1 metalist2) - "Destructively zip two alists into one. +(defun el-job-child--zip (meta-list1 meta-list2) + "Destructively zip two lists into one. Like the Dash expression \(-zip-with #\\='nconc list1 list2). -METALIST1 and METALIST2 must be proper lists of identical length, -and each element in them must be a proper list or nil." +META-LIST1 and META-LIST2 must be lists of identical length, +and each element in them must be a list or nil." (let (merged) - (while metalist1 - (push (nconc (pop metalist1) (pop metalist2)) + (while meta-list1 + (push (nconc (pop meta-list1) (pop meta-list2)) merged)) - (when metalist2 (error "Lists differed in length")) + (when meta-list2 (error "Lists differed in length")) (nreverse merged))) (defun el-job-child--receive-injection () diff --git a/el-job.el b/el-job.el index 30e0398a0b..abb89b6afe 100644 --- a/el-job.el +++ b/el-job.el @@ -97,15 +97,15 @@ editing." "Look for the .eln, .elc or .el file corresponding to FEATURE. FEATURE is a symbol such as those seen in `features'. -Guess which variant was in fact loaded by the current Emacs, -and return it if it is .elc or .eln. +See `el-job--locate-lib-in-load-history'. If it is .el, then opportunistically compile it and return the newly -compiled file instead. This returns an .elc on the first call, then an -.eln on future calls. +compiled file instead. This returns an .elc on the first call, then +most likely an .eln on future calls. -Note: if you are currently editing the source code for FEATURE, save it -and use \\[eval-buffer] to ensure this will find the correct file." +Note: if you are currently editing the source code for FEATURE, save +that file of source code and use \\[eval-buffer] to ensure this will +find the correct file." (let ((loaded (el-job--locate-lib-in-load-history feature))) (unless loaded (error "Current Lisp definitions must come from a file %S[.el/.elc/.eln]" @@ -114,6 +114,9 @@ and use \\[eval-buffer] to ensure this will find the correct file." ;; .el that's in load-path, instead. Bad hack, because load-path is ;; NOT as trustworthy as load-history (current Emacs may not be using ;; the thing in load-path). + ;; REVIEW: Can we actually remove the hack? I'd assume freefn- files are + ;; only created when the source file is unknown, which would best + ;; signal an error here. (when (string-search "freefn-" loaded) (setq loaded (locate-file (symbol-name feature) load-path '(".el" ".el.gz")))) @@ -157,18 +160,34 @@ and use \\[eval-buffer] to ensure this will find the correct file." ;; the point the developer actually evals the .el buffer. loaded))) +(defun el-job--split-evenly (big-list n &optional _) + "Split BIG-LIST into a list of up to N sublists. + +In the unlikely case where BIG-LIST contains N or fewer elements, +the result looks just like BIG-LIST except that +each element is wrapped in its own list." + (let ((sublist-length (max 1 (/ (length big-list) n))) + result) + (dotimes (i n) + (if (= i (1- n)) + ;; Let the last iteration just take what's left + (push big-list result) + (push (take sublist-length big-list) result) + (setq big-list (nthcdr sublist-length big-list)))) + (delq nil result))) + (defun el-job--split-optimally (items n-cores table) "Split ITEMS into up to N-CORES lists of items. For all keys in TABLE that match one of ITEMS, assume the value holds a benchmark \(a Lisp time value) for how long it took in the past to pass -this item through the FUNCALL function specified by `el-job-launch'. +this item through the FUNCALL-PER-INPUT function specified by `el-job-launch'. Use these benchmarks to rebalance the lists so that each sub-list should -take around the same total wall-time to work through this time. +take around the same amount of wall-time to work through. -This reduces the risk that one child takes noticably longer due to -being saddled with a mega-item in addition to the average workload." +This reduces the risk that one child takes markedly longer due to +being saddled with a huge item in addition to the average workload." (let ((total-duration 0)) (cond ((= n-cores 1) @@ -177,7 +196,7 @@ being saddled with a mega-item in addition to the average workload." (el-job--split-evenly items n-cores)) ((progn (dolist (item items) - (when-let ((dur (gethash item table))) + (when-let* ((dur (gethash item table))) (setq total-duration (time-add total-duration dur)))) (eq total-duration 0)) ;; Probably a first-time run @@ -214,7 +233,7 @@ being saddled with a mega-item in addition to the average workload." (push item items))))))) (if (length= sublists 0) (progn - (fset 'el-job--split-optimally 'el-job--split-evenly) + (fset 'el-job--split-optimally #'el-job--split-evenly) (error "el-job: Unexpected code path, report appreciated! Data: %S" (list 'n-cores n-cores 'total-duration total-duration @@ -233,22 +252,6 @@ being saddled with a mega-item in addition to the average workload." sublists))))) sublists))))) -(defun el-job--split-evenly (big-list n &optional _) - "Split BIG-LIST into a list of up to N sublists. - -In the unlikely case where BIG-LIST contains N or fewer elements, -the result looks just like BIG-LIST except that -each element is wrapped in its own list." - (let ((sublist-length (max 1 (/ (length big-list) n))) - result) - (dotimes (i n) - (if (= i (1- n)) - ;; Let the last iteration just take what's left - (push big-list result) - (push (take sublist-length big-list) result) - (setq big-list (nthcdr sublist-length big-list)))) - (delq nil result))) - (defun el-job--zip-all (meta-lists) "Destructively zip all META-LISTS into one. See subroutine `el-job-child--zip' for details." @@ -258,7 +261,7 @@ See subroutine `el-job-child--zip' for details." merged)) -;;; Main logic: +;;; Main logic (defvar el-job--machine-cores nil "Max amount of processes to spawn for one job. @@ -285,7 +288,7 @@ See `el-job-launch' for arguments." (el-job--exec job))) (defmacro el-job--with (job slots &rest body) - "Make SLOTS expand into object accessors for el-job JOB inside BODY. + "Make SLOTS expand into object accessors for `el-job' JOB inside BODY. Cf. `with-slots' in the eieio library, or `let-alist'. For clarity inside BODY, each symbol name in SLOTS must be prepended @@ -324,15 +327,15 @@ with one character of your choosing, such as a dot." ;;;###autoload (cl-defun el-job-launch ( &rest deprecated-args &key + id + if-busy load-features inject-vars - funcall-per-input inputs + funcall-per-input callback - id - if-busy keepalive ) - "Run FUNCALL in one or more headless Elisp processes. + "Run FUNCALL-PER-INPUT in one or more headless Elisp processes. Then merge the return values \(lists of N lists) into one list \(of N lists) and pass it to CALLBACK.